// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "vm/object.h" #include "include/dart_api.h" #include "platform/assert.h" #include "vm/assembler.h" #include "vm/cpu.h" #include "vm/bigint_operations.h" #include "vm/bootstrap.h" #include "vm/class_finalizer.h" #include "vm/code_generator.h" #include "vm/code_observers.h" #include "vm/code_patcher.h" #include "vm/compiler.h" #include "vm/compiler_stats.h" #include "vm/dart.h" #include "vm/dart_api_state.h" #include "vm/dart_entry.h" #include "vm/datastream.h" #include "vm/debugger.h" #include "vm/deopt_instructions.h" #include "vm/disassembler.h" #include "vm/double_conversion.h" #include "vm/exceptions.h" #include "vm/flow_graph_builder.h" #include "vm/growable_array.h" #include "vm/heap.h" #include "vm/intermediate_language.h" #include "vm/intrinsifier.h" #include "vm/longjump.h" #include "vm/object_id_ring.h" #include "vm/object_store.h" #include "vm/parser.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/timer.h" #include "vm/unicode.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, trace_disabling_optimized_code, false, "Trace disabling optimized code."); 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."); DECLARE_FLAG(bool, eliminate_type_checks); DECLARE_FLAG(bool, enable_type_checks); DECLARE_FLAG(bool, error_on_bad_override); DECLARE_FLAG(bool, trace_compiler); DECLARE_FLAG(bool, trace_deoptimization); DECLARE_FLAG(bool, trace_deoptimization_verbose); DECLARE_FLAG(bool, verbose_stacktrace); DECLARE_FLAG(charp, coverage_dir); 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; AbstractTypeArguments* Object::null_abstract_type_arguments_ = NULL; Array* Object::empty_array_ = 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; RawObject* Object::null_ = reinterpret_cast(RAW_NULL); RawClass* Object::class_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::dynamic_class_ = reinterpret_cast(RAW_NULL); RawClass* Object::void_class_ = reinterpret_cast(RAW_NULL); RawType* Object::dynamic_type_ = reinterpret_cast(RAW_NULL); RawType* Object::void_type_ = 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); const double MegamorphicCache::kLoadFactor = 0.75; // The following functions are marked as invisible, meaning they will be hidden // in the stack trace and will be hidden from reflective access. // (Library, class name, method name) #define INVISIBLE_LIST(V) \ V(CoreLibrary, Object, _noSuchMethod) \ V(CoreLibrary, Object, _as) \ V(CoreLibrary, Object, _instanceOf) \ V(CoreLibrary, _List, _List.) \ V(CoreLibrary, AssertionError, _throwNew) \ V(CoreLibrary, TypeError, _throwNew) \ V(CoreLibrary, FallThroughError, _throwNew) \ V(CoreLibrary, AbstractClassInstantiationError, _throwNew) \ V(CoreLibrary, int, _throwFormatException) \ V(CoreLibrary, int, _parse) \ V(CoreLibrary, StackTrace, _setupFullStackTrace) \ V(CoreLibrary, _OneByteString, _setAt) \ V(CoreLibrary, _StringBase, _substringUncheckedNative) \ V(CoreLibrary, _OneByteString, _substringUncheckedNative) \ V(CoreLibrary, _GrowableList, _setData) \ V(CoreLibrary, _GrowableList, _setLength) \ V(TypedDataLibrary, _TypedList, _getInt8) \ V(TypedDataLibrary, _TypedList, _setInt8) \ V(TypedDataLibrary, _TypedList, _getUint8) \ V(TypedDataLibrary, _TypedList, _setUint8) \ V(TypedDataLibrary, _TypedList, _getInt16) \ V(TypedDataLibrary, _TypedList, _setInt16) \ V(TypedDataLibrary, _TypedList, _getUint16) \ V(TypedDataLibrary, _TypedList, _setUint16) \ V(TypedDataLibrary, _TypedList, _getInt32) \ V(TypedDataLibrary, _TypedList, _setInt32) \ V(TypedDataLibrary, _TypedList, _getUint32) \ V(TypedDataLibrary, _TypedList, _setUint32) \ V(TypedDataLibrary, _TypedList, _getInt64) \ V(TypedDataLibrary, _TypedList, _setInt64) \ V(TypedDataLibrary, _TypedList, _getUint64) \ V(TypedDataLibrary, _TypedList, _setUint64) \ V(TypedDataLibrary, _TypedList, _getFloat32) \ V(TypedDataLibrary, _TypedList, _setFloat32) \ V(TypedDataLibrary, _TypedList, _getFloat64) \ V(TypedDataLibrary, _TypedList, _setFloat64) \ V(TypedDataLibrary, _TypedList, _getFloat32x4) \ V(TypedDataLibrary, _TypedList, _setFloat32x4) \ static void MarkFunctionAsInvisible(const Library& lib, const char* class_name, const char* function_name) { ASSERT(!lib.IsNull()); const Class& cls = Class::Handle( lib.LookupClassAllowPrivate(String::Handle(String::New(class_name)))); ASSERT(!cls.IsNull()); const Function& function = Function::Handle( cls.LookupFunctionAllowPrivate( String::Handle(String::New(function_name)))); ASSERT(!function.IsNull()); function.set_is_visible(false); } static void MarkInvisibleFunctions() { #define MARK_FUNCTION(lib, class_name, function_name) \ MarkFunctionAsInvisible(Library::Handle(Library::lib()), \ #class_name, #function_name); \ INVISIBLE_LIST(MARK_FUNCTION) #undef MARK_FUNCTION } // Takes a vm internal name and makes it suitable for external user. // // Examples: // // Internal getter and setter prefixes are changed: // // get:foo -> foo // set:foo -> foo= // // Private name mangling is removed, possibly multiple times: // // _ReceivePortImpl@6be832b -> _ReceivePortImpl // _ReceivePortImpl@6be832b._internal@6be832b -> _ReceivePortImpl._internal // _C@0x2b4ab9cc&_E@0x2b4ab9cc&_F@0x2b4ab9cc -> _C&_E&_F // // 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 // RawString* String::IdentifierPrettyName(const String& name) { if (name.Equals(Symbols::TopLevel())) { // Name of invisible top-level class. return Symbols::Empty().raw(); } // First remove all private name mangling. String& unmangled_name = String::Handle(Symbols::Empty().raw()); String& segment = String::Handle(); intptr_t start_pos = 0; for (intptr_t i = 0; i < name.Length(); i++) { if (name.CharAt(i) == '@') { // Append the current segment to the unmangled name. segment = String::SubString(name, start_pos, (i - start_pos)); unmangled_name = String::Concat(unmangled_name, segment); // Advance until past the name mangling. i++; // Skip the '@'. while ((i < name.Length()) && (name.CharAt(i) != '&') && (name.CharAt(i) != '.')) { i++; } start_pos = i; i--; // Account for for-loop increment. } } if (start_pos == 0) { // No name unmangling needed, reuse the name that was passed in. unmangled_name = name.raw(); } else if (name.Length() != start_pos) { // Append the last segment. segment = String::SubString(name, start_pos, (name.Length() - start_pos)); unmangled_name = String::Concat(unmangled_name, segment); } intptr_t len = unmangled_name.Length(); 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.CharAt(i) == ':') { ASSERT(start == 0); // Only one : is possible in getters or setters. if (unmangled_name.CharAt(0) == 's') { is_setter = true; } start = i + 1; } else if (unmangled_name.CharAt(i) == '.') { 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 unmangled_name.raw(); } // Drop the trailing dot if needed. intptr_t end = ((dot_pos + 1) == len) ? dot_pos : len; const String& result = String::Handle(String::SubString(unmangled_name, start, (end - start))); if (is_setter) { // Setters need to end with '='. return String::Concat(result, Symbols::Equals()); } return result.raw(); } 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 static bool IsSpecialCharacter(type value) { return ((value == '"') || (value == '\n') || (value == '\f') || (value == '\b') || (value == '\t') || (value == '\v') || (value == '\r') || (value == '\\') || (value == '$')); } 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'; } else if (value == '\\') { return '\\'; } else if (value == '$') { return '$'; } UNREACHABLE(); return '\0'; } static void DeleteWeakPersistentHandle(Dart_WeakPersistentHandle 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. null_object_ = Object::ReadOnlyHandle(); null_array_ = Array::ReadOnlyHandle(); null_string_ = String::ReadOnlyHandle(); null_instance_ = Instance::ReadOnlyHandle(); null_abstract_type_arguments_ = AbstractTypeArguments::ReadOnlyHandle(); empty_array_ = 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(); // 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()); } *null_object_ = Object::null(); *null_array_ = Array::null(); *null_string_ = String::null(); *null_instance_ = Instance::null(); *null_abstract_type_arguments_ = AbstractTypeArguments::null(); // 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::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(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(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(); unresolved_class_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