blob: 421ff4a3a365a4ed426ef017909dd66085a32f37 [file] [log] [blame]
// 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, 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, error_on_bad_type);
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<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::instantiated_type_arguments_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::patch_class_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::function_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::closure_data_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::redirection_data_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::field_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::literal_token_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::token_stream_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::script_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::library_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::library_prefix_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::namespace_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::code_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::instructions_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::stackmap_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::var_descriptors_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::exception_handlers_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::deopt_info_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::context_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::context_scope_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::icdata_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::megamorphic_cache_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::subtypetestcache_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::api_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::language_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::unhandled_exception_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::unwind_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
#undef RAW_NULL
const double MegamorphicCache::kLoadFactor = 0.75;
// The following functions are marked as invisible, meaning they will be hidden
// in the stack trace 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, _ObjectArray, _ObjectArray.) \
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(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
//
static RawString* 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();
}
template<typename type>
static bool IsSpecialCharacter(type value) {
return ((value == '"') ||
(value == '\n') ||
(value == '\f') ||
(value == '\b') ||
(value == '\t') ||
(value == '\v') ||
(value == '\r') ||
(value == '\\') ||
(value == '$'));
}
template<typename type>
static type SpecialCharacter(type value) {
if (value == '"') {
return '"';
} else if (value == '\n') {
return 'n';
} else if (value == '\f') {
return 'f';
} else if (value == '\b') {
return 'b';
} else if (value == '\t') {
return 't';
} else if (value == '\v') {
return 'v';
} else if (value == '\r') {
return 'r';
} else if (value == '\\') {
return '\\';
} else if (value == '$') {
return '$';
}
UNREACHABLE();
return '\0';
}
static void DeleteWeakPersistentHandle(Dart_WeakPersistentHandle handle) {
ApiState* state = Isolate::Current()->api_state();
ASSERT(state != NULL);
FinalizablePersistentHandle* weak_ref =
reinterpret_cast<FinalizablePersistentHandle*>(handle);
ASSERT(state->IsValidWeakPersistentHandle(handle));
state->weak_persistent_handles().FreeHandle(weak_ref);
}
void Object::InitOnce() {
// TODO(iposva): NoGCScope needs to be added here.
ASSERT(class_class() == null_);
// Initialize the static vtable values.
{
Object fake_object;
Smi fake_smi;
Object::handle_vtable_ = fake_object.vtable();
Smi::handle_vtable_ = fake_smi.vtable();
}
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
// Allocate the read only object handles here.
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<RawInstance*>(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<RawClass*>(address + kHeapObjectTag);
InitializeObject(address, Class::kClassId, size);
Class fake;
// Initialization from Class::New<Class>.
// Directly set raw_ to break a circular dependency: SetRaw will attempt
// to lookup class class in the class table where it is not registered yet.
cls.raw_ = class_class_;
cls.set_handle_vtable(fake.vtable());
cls.set_instance_size(Class::InstanceSize());
cls.set_next_field_offset(Class::InstanceSize());
cls.set_id(Class::kClassId);
cls.raw_ptr()->state_bits_ = 0;
cls.set_is_finalized();
cls.set_is_type_finalized();
cls.raw_ptr()->type_arguments_field_offset_in_words_ =
Class::kNoTypeArguments;
cls.raw_ptr()->num_native_fields_ = 0;
cls.InitEmptyFields();
isolate->RegisterClass(cls);
}
// Allocate and initialize the null class.
cls = Class::New<Instance>(kNullCid);
isolate->object_store()->set_null_class(cls);
// Allocate and initialize the free list element class.
cls = Class::New<FreeListElement::FakeInstance>(kFreeListElement);
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<InstantiatedTypeArguments>();
instantiated_type_arguments_class_ = cls.raw();
cls = Class::New<PatchClass>();
patch_class_class_ = cls.raw();
cls = Class::New<Function>();
function_class_ = cls.raw();
cls = Class::New<ClosureData>();
closure_data_class_ = cls.raw();
cls = Class::New<RedirectionData>();
redirection_data_class_ = cls.raw();
cls = Class::New<Field>();
field_class_ = cls.raw();
cls = Class::New<LiteralToken>();
literal_token_class_ = cls.raw();
cls = Class::New<TokenStream>();
token_stream_class_ = cls.raw();
cls = Class::New<Script>();
script_class_ = cls.raw();
cls = Class::New<Library>();
library_class_ = cls.raw();
cls = Class::New<LibraryPrefix>();
library_prefix_class_ = cls.raw();
cls = Class::New<Namespace>();
namespace_class_ = cls.raw();
cls = Class::New<Code>();
code_class_ = cls.raw();
cls = Class::New<Instructions>();
instructions_class_ = cls.raw();
cls = Class::New<PcDescriptors>();
pc_descriptors_class_ = cls.raw();
cls = Class::New<Stackmap>();
stackmap_class_ = cls.raw();
cls = Class::New<LocalVarDescriptors>();
var_descriptors_class_ = cls.raw();
cls = Class::New<ExceptionHandlers>();
exception_handlers_class_ = cls.raw();
cls = Class::New<DeoptInfo>();
deopt_info_class_ = cls.raw();
cls = Class::New<Context>();
context_class_ = cls.raw();
cls = Class::New<ContextScope>();
context_scope_class_ = cls.raw();
cls = Class::New<ICData>();
icdata_class_ = cls.raw();
cls = Class::New<MegamorphicCache>();
megamorphic_cache_class_ = cls.raw();
cls = Class::New<SubtypeTestCache>();
subtypetestcache_class_ = cls.raw();
cls = Class::New<ApiError>();
api_error_class_ = cls.raw();
cls = Class::New<LanguageError>();
language_error_class_ = cls.raw();
cls = Class::New<UnhandledException>();
unhandled_exception_class_ = cls.raw();
cls = Class::New<UnwindError>();
unwind_error_class_ = cls.raw();
ASSERT(class_class() != null_);
// Pre-allocate classes in the vm isolate so that we can for example create a
// symbol table and populate it with some frequently used strings as symbols.
cls = Class::New<Array>();
isolate->object_store()->set_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset());
cls = Class::New<Array>(kImmutableArrayCid);
isolate->object_store()->set_immutable_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset());
cls = Class::NewStringClass(kOneByteStringCid);
isolate->object_store()->set_one_byte_string_class(cls);
cls = Class::NewStringClass(kTwoByteStringCid);
isolate->object_store()->set_two_byte_string_class(cls);
// Allocate and initialize the empty_array instance.
{
uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld);
InitializeObject(address, kArrayCid, Array::InstanceSize(0));
Array::initializeHandle(
empty_array_,
reinterpret_cast<RawArray*>(address + kHeapObjectTag));
empty_array_->raw()->ptr()->length_ = Smi::New(0);
}
cls = Class::New<Instance>(kDynamicCid);
cls.set_is_finalized();
cls.set_is_type_finalized();
cls.set_is_abstract();
dynamic_class_ = cls.raw();
cls = Class::New<Instance>(kVoidCid);
cls.set_is_finalized();
cls.set_is_type_finalized();
void_class_ = cls.raw();
cls = Class::New<Type>();
cls.set_is_finalized();
cls.set_is_type_finalized();
isolate->object_store()->set_type_class(cls);
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");
*snapshot_writer_error_ = LanguageError::New(error_str);
error_str = String::New("Branch offset overflow");
*branch_offset_error_ = LanguageError::New(error_str);
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_abstract_type_arguments_->IsSmi());
ASSERT(null_abstract_type_arguments_->IsAbstractTypeArguments());
ASSERT(!empty_array_->IsSmi());
ASSERT(empty_array_->IsArray());
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());
}
#define SET_CLASS_NAME(class_name, name) \
cls = class_name##_class(); \
cls.set_name(Symbols::name()); \
void Object::RegisterSingletonClassNames() {
Class& cls = Class::Handle();
// Set up names for all VM singleton classes.
SET_CLASS_NAME(class, Class);
SET_CLASS_NAME(dynamic, Dynamic);
SET_CLASS_NAME(void, Void);
SET_CLASS_NAME(unresolved_class, UnresolvedClass);
SET_CLASS_NAME(type_arguments, TypeArguments);
SET_CLASS_NAME(instantiated_type_arguments, InstantiatedTypeArguments);
SET_CLASS_NAME(patch_class, PatchClass);
SET_CLASS_NAME(function, Function);
SET_CLASS_NAME(closure_data, ClosureData);
SET_CLASS_NAME(redirection_data, RedirectionData);
SET_CLASS_NAME(field, Field);
SET_CLASS_NAME(literal_token, LiteralToken);
SET_CLASS_NAME(token_stream, TokenStream);
SET_CLASS_NAME(script, Script);
SET_CLASS_NAME(library, LibraryClass);
SET_CLASS_NAME(library_prefix, LibraryPrefix);
SET_CLASS_NAME(namespace, Namespace);
SET_CLASS_NAME(code, Code);
SET_CLASS_NAME(instructions, Instructions);
SET_CLASS_NAME(pc_descriptors, PcDescriptors);
SET_CLASS_NAME(stackmap, Stackmap);
SET_CLASS_NAME(var_descriptors, LocalVarDescriptors);
SET_CLASS_NAME(exception_handlers, ExceptionHandlers);
SET_CLASS_NAME(deopt_info, DeoptInfo);
SET_CLASS_NAME(context, Context);
SET_CLASS_NAME(context_scope, ContextScope);
SET_CLASS_NAME(icdata, ICData);
SET_CLASS_NAME(megamorphic_cache, MegamorphicCache);
SET_CLASS_NAME(subtypetestcache, SubtypeTestCache);
SET_CLASS_NAME(api_error, ApiError);
SET_CLASS_NAME(language_error, LanguageError);
SET_CLASS_NAME(unhandled_exception, UnhandledException);
SET_CLASS_NAME(unwind_error, UnwindError);
// Set up names for object array and one byte string class which are
// pre-allocated in the vm isolate also.
cls = Dart::vm_isolate()->object_store()->array_class();
cls.set_name(Symbols::ObjectArray());
cls = Dart::vm_isolate()->object_store()->one_byte_string_class();
cls.set_name(Symbols::OneByteString());
}
void Object::CreateInternalMetaData() {
// Initialize meta data for VM internal classes.
Class& cls = Class::Handle();
Array& fields = Array::Handle();
Field& fld = Field::Handle();
String& name = String::Handle();
// TODO(iposva): Add more of the VM classes here.
cls = context_class_;
fields = Array::New(1);
name = Symbols::New("@parent_");
fld = Field::New(name, false, false, false, cls, 0);
fields.SetAt(0, fld);
cls.SetFields(fields);
}
// Make unused space in an object whose type has been transformed safe
// for traversing during GC.
// The unused part of the transformed object is marked as an TypedDataInt8Array
// object.
void Object::MakeUnusedSpaceTraversable(const Object& obj,
intptr_t original_size,
intptr_t used_size) {
ASSERT(Isolate::Current()->no_gc_scope_depth() > 0);
ASSERT(!obj.IsNull());
ASSERT(original_size >= used_size);
if (original_size > used_size) {
intptr_t leftover_size = original_size - used_size;
uword addr = RawObject::ToAddr(obj.raw()) + used_size;
if (leftover_size >= TypedData::InstanceSize(0)) {
// Update the leftover space as an TypedDataInt8Array object.
RawTypedData* raw =
reinterpret_cast<RawTypedData*>(RawObject::FromAddr(addr));
uword tags = 0;
tags = RawObject::SizeTag::update(leftover_size, tags);
tags = RawObject::ClassIdTag::update(kTypedDataInt8ArrayCid, tags);
raw->ptr()->tags_ = tags;
intptr_t leftover_len = (leftover_size - TypedData::InstanceSize(0));
ASSERT(TypedData::InstanceSize(leftover_len) == leftover_size);
raw->ptr()->length_ = Smi::New(leftover_len);
} else {
// Update the leftover space as a basic object.
ASSERT(leftover_size == Object::InstanceSize());
RawObject* raw = reinterpret_cast<RawObject*>(RawObject::FromAddr(addr));
uword tags = 0;
tags = RawObject::SizeTag::update(leftover_size, tags);
tags = RawObject::ClassIdTag::update(kInstanceCid, tags);
raw->ptr()->tags_ = tags;
}
}
}
void Object::VerifyBuiltinVtables() {
#if defined(DEBUG)
Isolate* isolate = Isolate::Current();
ASSERT(isolate != NULL);
Class& cls = Class::Handle(isolate, Class::null());
for (intptr_t cid = (kIllegalCid + 1); cid < kNumPredefinedCids; cid++) {
if (isolate->class_table()->HasValidClassAt(cid)) {
cls ^= isolate->class_table()->At(cid);
ASSERT(builtin_vtables_[cid] == cls.raw_ptr()->handle_vtable_);
}
}
#endif
}
void Object::RegisterClass(const Class& cls,
const String& name,
const Library& lib) {
ASSERT(name.Length() > 0);
ASSERT(name.CharAt(0) != '_');
cls.set_name(name);
lib.AddClass(cls);
}
void Object::RegisterPrivateClass(const Class& cls,
const String& public_class_name,
const Library& lib) {
ASSERT(public_class_name.Length() > 0);
ASSERT(public_class_name.CharAt(0) == '_');
String& str = String::Handle();
str = lib.PrivateName(public_class_name);
cls.set_name(str);
lib.AddClass(cls);
}
RawError* Object::Init(Isolate* isolate) {
TIMERSCOPE(time_bootstrap);
ObjectStore* object_store = isolate->object_store();
Class& cls = Class::Handle();
Type& type = Type::Handle();
Array& array = Array::Handle();
Library& lib = Library::Handle();
// All RawArray fields will be initialized to an empty array, therefore
// initialize array class first.
cls = Class::New<Array>();
object_store->set_array_class(cls);
// Array and ImmutableArray are the only VM classes that are parameterized.
// Since they are pre-finalized, CalculateFieldOffsets() is not called, so we
// need to set the offset of their type_arguments_ field, which is explicitly
// declared in RawArray.
cls.set_type_arguments_field_offset(Array::type_arguments_offset());
// Set up the growable object array class (Has to be done after the array
// class is setup as one of its field is an array object).
cls = Class::New<GrowableObjectArray>();
object_store->set_growable_object_array_class(cls);
cls.set_type_arguments_field_offset(
GrowableObjectArray::type_arguments_offset());
// canonical_type_arguments_ are Smi terminated.
// Last element contains the count of used slots.
const intptr_t kInitialCanonicalTypeArgumentsSize = 4;
array = Array::New(kInitialCanonicalTypeArgumentsSize + 1);
array.SetAt(kInitialCanonicalTypeArgumentsSize, Smi::Handle(Smi::New(0)));
object_store->set_canonical_type_arguments(array);
// Setup type class early in the process.
cls = Class::New<Type>();
object_store->set_type_class(cls);
cls = Class::New<TypeParameter>();
object_store->set_type_parameter_class(cls);
cls = Class::New<BoundedType>();
object_store->set_bounded_type_class(cls);
cls = Class::New<MixinAppType>();
object_store->set_mixin_app_type_class(cls);
// Pre-allocate the OneByteString class needed by the symbol table.
cls = Class::NewStringClass(kOneByteStringCid);
object_store->set_one_byte_string_class(cls);
// Pre-allocate the TwoByteString class needed by the symbol table.
cls = Class::NewStringClass(kTwoByteStringCid);
object_store->set_two_byte_string_class(cls);
// Setup the symbol table for the symbols created in the isolate.
Symbols::SetupSymbolTable(isolate);
// Set up the libraries array before initializing the core library.
const GrowableObjectArray& libraries =
GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld));
object_store->set_libraries(libraries);
// Pre-register the core library.
Library::InitCoreLibrary(isolate);
// Basic infrastructure has been setup, initialize the class dictionary.
Library& core_lib = Library::Handle(Library::CoreLibrary());
ASSERT(!core_lib.IsNull());
const GrowableObjectArray& pending_classes =
GrowableObjectArray::Handle(GrowableObjectArray::New());
object_store->set_pending_classes(pending_classes);
Context& context = Context::Handle(Context::New(0, Heap::kOld));
object_store->set_empty_context(context);
// Now that the symbol table is initialized and that the core dictionary as
// well as the core implementation dictionary have been setup, preallocate
// remaining classes and register them by name in the dictionaries.
String& name = String::Handle();
cls = object_store->array_class(); // Was allocated above.
RegisterPrivateClass(cls, Symbols::ObjectArray(), core_lib);
pending_classes.Add(cls);
// We cannot use NewNonParameterizedType(cls), because Array is parameterized.
type ^= Type::New(Object::Handle(cls.raw()),
TypeArguments::Handle(),
Scanner::kDummyTokenIndex);
type.SetIsFinalized();
type ^= type.Canonicalize();
object_store->set_array_type(type);
cls = object_store->growable_object_array_class(); // Was allocated above.
RegisterPrivateClass(cls, Symbols::GrowableObjectArray(), core_lib);
pending_classes.Add(cls);
cls = Class::New<Array>(kImmutableArrayCid);
object_store->set_immutable_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset());
ASSERT(object_store->immutable_array_class() != object_store->array_class());
cls.set_is_prefinalized();
RegisterPrivateClass(cls, Symbols::ImmutableArray(), 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);
cls = Class::New<Stacktrace>();
object_store->set_stacktrace_class(cls);
RegisterClass(cls, Symbols::StackTrace(), core_lib);
pending_classes.Add(cls);
// Super type set below, after Object is allocated.
cls = Class::New<JSRegExp>();
object_store->set_jsregexp_class(cls);
RegisterPrivateClass(cls, Symbols::JSSyntaxRegExp(), core_lib);
pending_classes.Add(cls);
// 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_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);
cls.set_is_prefinalized();
object_store->set_null_class(cls);
RegisterClass(cls, Symbols::Null(), core_lib);
pending_classes.Add(cls);
cls = object_store->type_class();
RegisterPrivateClass(cls, Symbols::Type(), core_lib);
pending_classes.Add(cls);
cls = object_store->type_parameter_class();
RegisterPrivateClass(cls, Symbols::TypeParameter(), core_lib);
pending_classes.Add(cls);
cls = object_store->bounded_type_class();
RegisterPrivateClass(cls, Symbols::BoundedType(), core_lib);
pending_classes.Add(cls);
cls = object_store->mixin_app_type_class();
RegisterPrivateClass(cls, Symbols::MixinAppType(), core_lib);
pending_classes.Add(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_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.Register();
isolate->object_store()->set_bootstrap_library(ObjectStore::kMirrors,
lib);
}
ASSERT(!lib.IsNull());
ASSERT(lib.raw() == Library::MirrorsLibrary());
cls = Class::New<MirrorReference>();
object_store->set_mirror_reference_class(cls);
RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
// Setup some default native field classes which can be extended for
// specifying native fields in dart classes.
Library::InitNativeWrappersLibrary(isolate);
ASSERT(isolate->object_store()->native_wrappers_library() != Library::null());
// Pre-register the typed_data library so the native class implementations
// can be hooked up before compiling it.
lib = Library::LookupLibrary(Symbols::DartTypedData());
if (lib.IsNull()) {
lib = Library::NewLibraryHelper(Symbols::DartTypedData(), true);
lib.Register();
isolate->object_store()->set_bootstrap_library(ObjectStore::kTypedData,
lib);
}
ASSERT(!lib.IsNull());
ASSERT(lib.raw() == Library::TypedDataLibrary());
const intptr_t typed_data_class_array_length =
RawObject::NumberOfTypedDataClasses();
Array& typed_data_classes =
Array::Handle(Array::New(typed_data_class_array_length));
int index = 0;
#define REGISTER_TYPED_DATA_CLASS(clazz) \
cls = Class::NewTypedDataClass(kTypedData##clazz##Cid); \
index = kTypedData##clazz##Cid - kTypedDataInt8ArrayCid; \
typed_data_classes.SetAt(index, cls); \
RegisterPrivateClass(cls, Symbols::_##clazz(), lib); \
CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
#undef REGISTER_TYPED_DATA_CLASS
#define REGISTER_TYPED_DATA_VIEW_CLASS(clazz) \
cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid); \
index = kTypedData##clazz##ViewCid - kTypedDataInt8ArrayCid; \
typed_data_classes.SetAt(index, cls); \
RegisterPrivateClass(cls, Symbols::_##clazz##View(), lib); \
pending_classes.Add(cls); \
CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
cls = Class::NewTypedDataViewClass(kByteDataViewCid);
index = kByteDataViewCid - kTypedDataInt8ArrayCid;
typed_data_classes.SetAt(index, cls);
RegisterPrivateClass(cls, Symbols::_ByteDataView(), lib);
pending_classes.Add(cls);
#undef REGISTER_TYPED_DATA_VIEW_CLASS
#define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \
cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid); \
index = kExternalTypedData##clazz##Cid - kTypedDataInt8ArrayCid; \
typed_data_classes.SetAt(index, cls); \
RegisterPrivateClass(cls, Symbols::_External##clazz(), lib); \
CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
#undef REGISTER_EXT_TYPED_DATA_CLASS
// Register Float32x4 and Uint32x4 in the object store.
cls = Class::New<Float32x4>();
object_store->set_float32x4_class(cls);
RegisterPrivateClass(cls, Symbols::_Float32x4(), lib);
cls = Class::New<Uint32x4>();
object_store->set_uint32x4_class(cls);
RegisterPrivateClass(cls, Symbols::_Uint32x4(), lib);
cls = Class::New<Instance>(kIllegalCid);
RegisterClass(cls, Symbols::Float32x4(), lib);
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::Uint32x4(), lib);
cls.set_is_prefinalized();
pending_classes.Add(cls);
type = Type::NewNonParameterizedType(cls);
object_store->set_uint32x4_type(type);
object_store->set_typed_data_classes(typed_data_classes);
// Set the super type of class Stacktrace to Object type so that the
// 'toString' method is implemented.
cls = object_store->stacktrace_class();
type = object_store->object_type();
cls.set_super_type(type);
// Abstract class that represents the Dart class Function.
cls = Class::New<Instance>(kIllegalCid);
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_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_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_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();
MarkInvisibleFunctions();
// Set up the intrinsic state of all functions (core, math and scalar list).
Intrinsifier::InitializeState();
return Error::null();
}
void Object::InitFromSnapshot(Isolate* isolate) {
TIMERSCOPE(time_bootstrap);
ObjectStore* object_store = isolate->object_store();
Class& cls = Class::Handle();
// Set up empty classes in the object store, these will get
// initialized correctly when we read from the snapshot.
// This is done to allow bootstrapping of reading classes from the snapshot.
cls = Class::New<Instance>(kInstanceCid);
object_store->set_object_class(cls);
cls = Class::New<Type>();
object_store->set_type_class(cls);
cls = Class::New<TypeParameter>();
object_store->set_type_parameter_class(cls);
cls = Class::New<BoundedType>();
object_store->set_bounded_type_class(cls);
cls = Class::New<MixinAppType>();
object_store->set_mixin_app_type_class(cls);
cls = Class::New<Array>();
object_store->set_array_class(cls);
cls = Class::New<Array>(kImmutableArrayCid);
object_store->set_immutable_array_class(cls);
cls = Class::New<GrowableObjectArray>();
object_store->set_growable_object_array_class(cls);
cls = Class::New<Float32x4>();
object_store->set_float32x4_class(cls);
cls = Class::New<Uint32x4>();
object_store->set_uint32x4_class(cls);
#define REGISTER_TYPED_DATA_CLASS(clazz) \
cls = Class::NewTypedDataClass(kTypedData##clazz##Cid);
CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
#undef REGISTER_TYPED_DATA_CLASS
#define REGISTER_TYPED_DATA_VIEW_CLASS(clazz) \
cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid);
CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
cls = Class::NewTypedDataViewClass(kByteDataViewCid);
#undef REGISTER_TYPED_DATA_VIEW_CLASS
#define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \
cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid);
CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
#undef REGISTER_EXT_TYPED_DATA_CLASS
cls = Class::New<Integer>();
object_store->set_integer_implementation_class(cls);
cls = Class::New<Smi>();
object_store->set_smi_class(cls);
cls = Class::New<Mint>();
object_store->set_mint_class(cls);
cls = Class::New<Double>();
object_store->set_double_class(cls);
cls = Class::New<Bigint>();
object_store->set_bigint_class(cls);
cls = Class::NewStringClass(kOneByteStringCid);
object_store->set_one_byte_string_class(cls);
cls = Class::NewStringClass(kTwoByteStringCid);
object_store->set_two_byte_string_class(cls);
cls = Class::NewStringClass(kExternalOneByteStringCid);
object_store->set_external_one_byte_string_class(cls);
cls = Class::NewStringClass(kExternalTwoByteStringCid);
object_store->set_external_two_byte_string_class(cls);
cls = Class::New<Bool>();
object_store->set_bool_class(cls);
cls = Class::New<Instance>(kNullCid);
object_store->set_null_class(cls);
cls = Class::New<Stacktrace>();
object_store->set_stacktrace_class(cls);
cls = Class::New<JSRegExp>();
object_store->set_jsregexp_class(cls);
// Some classes are not stored in the object store. Yet we still need to
// create their Class object so that they get put into the class_table
// (as a side effect of Class::New()).
cls = Class::New<Number>();
cls = Class::New<WeakProperty>();
object_store->set_weak_property_class(cls);
cls = Class::New<MirrorReference>();
object_store->set_mirror_reference_class(cls);
}
void Object::Print() const {
OS::Print("%s\n", ToCString());
}
RawString* Object::DictionaryName() const {
return String::null();
}
void Object::InitializeObject(uword address, intptr_t class_id, intptr_t size) {
// TODO(iposva): Get a proper halt instruction from the assembler which
// would be needed here for code objects.
uword initial_value = reinterpret_cast<uword>(null_);
uword cur = address;
uword end = address + size;
while (cur < end) {
*reinterpret_cast<uword*>(cur) = initial_value;
cur += kWordSize;
}
uword tags = 0;
ASSERT(class_id != kIllegalCid);
tags = RawObject::ClassIdTag::update(class_id, tags);
tags = RawObject::SizeTag::update(size, tags);
reinterpret_cast<RawObject*>(address)->tags_ = tags;
}
void Object::CheckHandle() const {
#if defined(DEBUG)
if (raw_ != Object::null()) {
if ((reinterpret_cast<uword>(raw_) & kSmiTagMask) == kSmiTag) {
ASSERT(vtable() == Smi::handle_vtable_);
return;
}
intptr_t cid = raw_->GetClassId();
if (cid >= kNumPredefinedCids) {
cid = kInstanceCid;
}
ASSERT(vtable() == builtin_vtables_[cid]);
if (FLAG_verify_handles) {
Isolate* isolate = Isolate::Current();
Heap* isolate_heap = isolate->heap();
Heap* vm_isolate_heap = Dart::vm_isolate()->heap();
ASSERT(isolate_heap->Contains(RawObject::ToAddr(raw_)) ||
vm_isolate_heap->Contains(RawObject::ToAddr(raw_)));
}
}
#endif
}
RawObject* Object::Allocate(intptr_t cls_id,
intptr_t size,
Heap::Space space) {
ASSERT(Utils::IsAligned(size, kObjectAlignment));
Isolate* isolate = Isolate::Current();
ASSERT(isolate->no_callback_scope_depth() == 0);
Heap* heap = isolate->heap();
uword address = heap->Allocate(size, space);
if (address == 0) {
// Use the preallocated out of memory exception to avoid calling
// into dart code or allocating any code.
const Instance& exception =
Instance::Handle(isolate->object_store()->out_of_memory());
Exceptions::Throw(exception);
UNREACHABLE();
}
NoGCScope no_gc;
InitializeObject(address, cls_id, size);
RawObject* raw_obj = reinterpret_cast<RawObject*>(address + kHeapObjectTag);
ASSERT(cls_id == RawObject::ClassIdTag::decode(raw_obj->ptr()->tags_));
return raw_obj;
}
class StoreBufferUpdateVisitor : public ObjectPointerVisitor {
public:
explicit StoreBufferUpdateVisitor(Isolate* isolate, RawObject* obj) :
ObjectPointerVisitor(isolate), old_obj_(obj) {
ASSERT(old_obj_->IsOldObject());
}
void VisitPointers(RawObject** first, RawObject** last) {
for (RawObject** curr = first; curr <= last; ++curr) {
RawObject* raw_obj = *curr;
if (raw_obj->IsHeapObject() && raw_obj->IsNewObject()) {
old_obj_->SetRememberedBit();
isolate()->store_buffer()->AddObject(old_obj_);
// Remembered this object. There is no need to continue searching.
return;
}
}
}
private:
RawObject* old_obj_;
DISALLOW_COPY_AND_ASSIGN(StoreBufferUpdateVisitor);
};
bool Object::IsReadOnlyHandle() const {
return Dart::IsReadOnlyHandle(reinterpret_cast<uword>(this));
}
bool Object::IsNotTemporaryScopedHandle() const {
return (IsZoneHandle() || IsReadOnlyHandle());
}
RawObject* Object::Clone(const Object& src, Heap::Space space) {
const Class& cls = Class::Handle(src.clazz());
intptr_t size = src.raw()->Size();
RawObject* raw_obj = Object::Allocate(cls.id(), size, space);
NoGCScope no_gc;
memmove(raw_obj->ptr(), src.raw()->ptr(), size);
if ((space == Heap::kOld) && !raw_obj->IsRemembered()) {
StoreBufferUpdateVisitor visitor(Isolate::Current(), raw_obj);
raw_obj->VisitPointers(&visitor);
}
return raw_obj;
}
RawString* Class::Name() const {
ASSERT(raw_ptr()->name_ != String::null());
return raw_ptr()->name_;
}
RawString* Class::UserVisibleName() const {
if (FLAG_show_internal_names) {
return Name();
}
switch (id()) {
case kIntegerCid:
case kSmiCid:
case kMintCid:
case kBigintCid:
return Symbols::Int().raw();
case kDoubleCid:
return Symbols::Double().raw();
case kOneByteStringCid:
case kTwoByteStringCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
return Symbols::New("String");
case kArrayCid:
case kImmutableArrayCid:
case kGrowableObjectArrayCid:
return Symbols::List().raw();
case kFloat32x4Cid:
return Symbols::Float32x4().raw();
case kUint32x4Cid:
return Symbols::Uint32x4().raw();
case kTypedDataInt8ArrayCid:
case kExternalTypedDataInt8ArrayCid:
return Symbols::Int8List().raw();
case kTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ArrayCid:
return Symbols::Uint8List().raw();
case kTypedDataUint8ClampedArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
return Symbols::Uint8ClampedList().raw();
case kTypedDataInt16ArrayCid:
case kExternalTypedDataInt16ArrayCid:
return Symbols::Int16List().raw();
case kTypedDataUint16ArrayCid:
case kExternalTypedDataUint16ArrayCid:
return Symbols::Uint16List().raw();
case kTypedDataInt32ArrayCid:
case kExternalTypedDataInt32ArrayCid:
return Symbols::Int32List().raw();
case kTypedDataUint32ArrayCid:
case kExternalTypedDataUint32ArrayCid:
return Symbols::Uint32List().raw();
case kTypedDataInt64ArrayCid:
case kExternalTypedDataInt64ArrayCid:
return Symbols::Int64List().raw();
case kTypedDataUint64ArrayCid:
case kExternalTypedDataUint64ArrayCid:
return Symbols::Uint64List().raw();
case kTypedDataFloat32x4ArrayCid:
case kExternalTypedDataFloat32x4ArrayCid:
return Symbols::Float32x4List().raw();
case kTypedDataFloat32ArrayCid:
case kExternalTypedDataFloat32ArrayCid:
return Symbols::Float32List().raw();
case kTypedDataFloat64ArrayCid:
case kExternalTypedDataFloat64ArrayCid:
return Symbols::Float64List().raw();
default:
if (!IsSignatureClass()) {
const String& name = String::Handle(Name());
return IdentifierPrettyName(name);
} else {
return Name();
}
}
UNREACHABLE();
}
RawType* Class::SignatureType() const {
ASSERT(IsSignatureClass());
const Function& function = Function::Handle(signature_function());
ASSERT(!function.IsNull());
if (function.signature_class() != raw()) {
// This class is a function type alias. Return the canonical signature type.
const Class& canonical_class = Class::Handle(function.signature_class());
return canonical_class.SignatureType();
}
// Return the first canonical signature type if already computed at class
// finalization time. The optimizer may canonicalize instantiated function
// types of the same signature class, but these will be added after the
// uninstantiated signature class at index 0.
const Array& signature_types = Array::Handle(canonical_types());
// The canonical_types array is initialized to the empty array.
ASSERT(!signature_types.IsNull());
if (signature_types.Length() > 0) {
Type& signature_type = Type::Handle();
signature_type ^= signature_types.At(0);
ASSERT(!signature_type.IsNull());
return signature_type.raw();
}
// A signature class extends class Instance and is parameterized in the same
// way as the owner class of its non-static signature function.
// It is not type parameterized if its signature function is static.
// See Class::NewSignatureClass() for the setup of its type parameters.
// During type finalization, the type arguments of the super class of the
// owner class of its signature function will be prepended to the type
// argument vector. Therefore, we only need to set the type arguments
// matching the type parameters here.
const TypeArguments& signature_type_arguments =
TypeArguments::Handle(type_parameters());
const Type& signature_type = Type::Handle(
Type::New(*this, signature_type_arguments, token_pos()));
// Return the still unfinalized signature type.
ASSERT(!signature_type.IsFinalized());
return signature_type.raw();
}
RawType* Class::RareType() const {
const Type& type = Type::Handle(Type::New(
*this,
Object::null_abstract_type_arguments(),
Scanner::kDummyTokenIndex));
return Type::RawCast(
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);
NoGCScope no_gc;
result ^= raw;
}
FakeObject fake;
result.set_handle_vtable(fake.vtable());
result.set_instance_size(FakeObject::InstanceSize());
result.set_next_field_offset(FakeObject::InstanceSize());
ASSERT((FakeObject::kClassId != kInstanceCid));
result.set_id(FakeObject::kClassId);
result.raw_ptr()->state_bits_ = 0;
// VM backed classes are almost ready: run checks and resolve class
// references, but do not recompute size.
result.set_is_prefinalized();
result.raw_ptr()->type_arguments_field_offset_in_words_ = kNoTypeArguments;
result.raw_ptr()->num_native_fields_ = 0;
result.raw_ptr()->token_pos_ = Scanner::kDummyTokenIndex;
result.InitEmptyFields();
Isolate::Current()->RegisterClass(result);
return result.raw();
}
// Initialize class fields of type Array with empty array.
void Class::InitEmptyFields() {
if (Object::empty_array().raw() == Array::null()) {
// The empty array has not been initialized yet.
return;
}
StorePointer(&raw_ptr()->interfaces_, Object::empty_array().raw());
StorePointer(&raw_ptr()->constants_, Object::empty_array().raw());
StorePointer(&raw_ptr()->canonical_types_, Object::empty_array().raw());
StorePointer(&raw_ptr()->functions_, Object::empty_array().raw());
StorePointer(&raw_ptr()->fields_, Object::empty_array().raw());
StorePointer(&raw_ptr()->invocation_dispatcher_cache_,
Object::empty_array().raw());
}
bool Class::HasInstanceFields() const {
const Array& field_array = Array::Handle(fields());
Field& field = Field::Handle();
for (intptr_t i = 0; i < field_array.Length(); ++i) {
field ^= field_array.At(i);
if (!field.is_static()) {
return true;
}
}
return false;
}
void Class::SetFunctions(const Array& value) const {
ASSERT(!value.IsNull());
#if defined(DEBUG)
// Verify that all the functions in the array have this class as owner.
Function& func = Function::Handle();
intptr_t len = value.Length();
for (intptr_t i = 0; i < len; i++) {
func ^= value.At(i);
ASSERT(func.Owner() == raw());
}
#endif
StorePointer(&raw_ptr()->functions_, value.raw());
}
void Class::AddFunction(const Function& function) const {
const Array& arr = Array::Handle(functions());
const Array& new_arr = Array::Handle(Array::Grow(arr, arr.Length() + 1));
new_arr.SetAt(arr.Length(), function);
SetFunctions(new_arr);
}
void Class::AddClosureFunction(const Function& function) const {
GrowableObjectArray& closures =
GrowableObjectArray::Handle(raw_ptr()->closure_functions_);
if (closures.IsNull()) {
closures = GrowableObjectArray::New(4);
StorePointer(&raw_ptr()->closure_functions_, closures.raw());
}
ASSERT(function.IsNonImplicitClosureFunction());
closures.Add(function);
}
// Lookup the innermost closure function that contains token at token_pos.
RawFunction* Class::LookupClosureFunction(intptr_t token_pos) const {
if (raw_ptr()->closure_functions_ == GrowableObjectArray::null()) {
return Function::null();
}
const GrowableObjectArray& closures =
GrowableObjectArray::Handle(raw_ptr()->closure_functions_);
Function& closure = Function::Handle();
intptr_t num_closures = closures.Length();
intptr_t best_fit_token_pos = -1;
intptr_t best_fit_index = -1;
for (intptr_t i = 0; i < num_closures; i++) {
closure ^= closures.At(i);
ASSERT(!closure.IsNull());
if ((closure.token_pos() <= token_pos) &&
(token_pos < closure.end_token_pos()) &&
(best_fit_token_pos < closure.token_pos())) {
best_fit_index = i;
best_fit_token_pos = closure.token_pos();
}
}
closure = Function::null();
if (best_fit_index >= 0) {
closure ^= closures.At(best_fit_index);
}
return closure.raw();
}
void Class::set_signature_function(const Function& value) const {
ASSERT(value.IsClosureFunction() || value.IsSignatureFunction());
StorePointer(&raw_ptr()->signature_function_, value.raw());
}
void Class::set_state_bits(intptr_t bits) const {
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() const {
if (IsMixinApplication() && !is_mixin_type_applied()) {
ClassFinalizer::ApplyMixinType(*this);
}
if (type_parameters() == TypeArguments::null()) {
return 0;
}
const TypeArguments& type_params = TypeArguments::Handle(type_parameters());
return type_params.Length();
}
intptr_t Class::NumTypeArguments() const {
// To work properly, this call requires the super class of this class to be
// resolved, which is checked by the type_class() call on the super type.
// Note that calling type_class() on a MixinAppType fails.
Isolate* isolate = Isolate::Current();
Class& cls = Class::Handle(isolate);
TypeArguments& type_params = TypeArguments::Handle(isolate);
AbstractType& sup_type = AbstractType::Handle(isolate);
cls ^= raw();
intptr_t num_type_args = 0;
do {
if (cls.IsSignatureClass()) {
Function& signature_fun = Function::Handle(isolate);
signature_fun ^= cls.signature_function();
if (!signature_fun.is_static() &&
!signature_fun.HasInstantiatedSignature()) {
cls = signature_fun.Owner();
}
}
// Calling NumTypeParameters() on a mixin application class will setup the
// type parameters if not already done.
if (cls.NumTypeParameters() > 0) {
type_params ^= cls.type_parameters();
num_type_args += type_params.Length();
}
// 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();
cls = sup_type.type_class();
} while (true);
return num_type_args;
}
bool Class::HasTypeArguments() const {
if (!IsSignatureClass() && (is_finalized() || is_prefinalized())) {
// More efficient than calling NumTypeArguments().
return type_arguments_field_offset() != kNoTypeArguments;
} else {
// No need to check NumTypeArguments() if class has type parameters.
return (NumTypeParameters() > 0) || (NumTypeArguments() > 0);
}
}
RawClass* Class::SuperClass() const {
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.IsBoundedType() ||
value.IsMixinAppType());
StorePointer(&raw_ptr()->super_type_, value.raw());
}
// Return a TypeParameter if the type_name is a type parameter of this class.
// Return null otherwise.
RawTypeParameter* Class::LookupTypeParameter(const String& type_name) const {
ASSERT(!type_name.IsNull());
Isolate* isolate = Isolate::Current();
ReusableHandleScope reused_handles(isolate);
TypeArguments& type_params = reused_handles.TypeArgumentsHandle();
type_params ^= type_parameters();
TypeParameter& type_param = reused_handles.TypeParameterHandle();
String& type_param_name = reused_handles.StringHandle();
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 = sizeof(RawObject);
} 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) 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()) {
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.
*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)));
}
// Named parameters.
for (; i < desc.Count(); i++) {
invocation.SetParameterTypeAt(i, Type::Handle(Type::DynamicType()));
intptr_t index = i - desc.PositionalCount();
invocation.SetParameterNameAt(i, String::Handle(desc.NameAt(index)));
}
invocation.set_result_type(Type::Handle(Type::DynamicType()));
invocation.set_is_visible(false); // Not visible in stack trace.
invocation.set_saved_args_desc(args_desc);
return invocation.raw();
}
RawArray* Class::invocation_dispatcher_cache() const {
return raw_ptr()->invocation_dispatcher_cache_;
}
void Class::set_invocation_dispatcher_cache(const Array& cache) const {
StorePointer(&raw_ptr()->invocation_dispatcher_cache_, cache.raw());
}
void Class::Finalize() const {
ASSERT(!is_finalized());
// Prefinalized classes have a VM internal representation and no Dart fields.
// Their instance size is precomputed and field offsets are known.
if (!is_prefinalized()) {
// Compute offsets of instance fields and instance size.
CalculateFieldOffsets();
}
set_is_finalized();
}
static RawError* FormatError(const Error& prev_error,
const Script& script,
intptr_t token_pos,
const char* format, ...) {
va_list args;
va_start(args, format);
if (prev_error.IsNull()) {
return Parser::FormatError(script, token_pos, "Error", format, args);
} else {
return Parser::FormatErrorWithAppend(prev_error, script, token_pos,
"Error", format, args);
}
}
// Apply the members from the patch class to the original class.
bool Class::ApplyPatch(const Class& patch, Error* error) const {
ASSERT(error != NULL);
ASSERT(!is_finalized());
// Shared handles used during the iteration.
String& member_name = String::Handle();
const PatchClass& patch_class =
PatchClass::Handle(PatchClass::New(*this, patch));
Array& orig_list = Array::Handle(functions());
intptr_t orig_len = orig_list.Length();
Array& patch_list = Array::Handle(patch.functions());
intptr_t patch_len = patch_list.Length();
// TODO(iposva): Verify that only patching existing methods and adding only
// new private methods.
Function& func = Function::Handle();
Function& orig_func = Function::Handle();
// Lookup the original implicit constructor, if any.
member_name = Name();
member_name = String::Concat(member_name, Symbols::Dot());
Function& orig_implicit_ctor = Function::Handle(LookupFunction(member_name));
if (!orig_implicit_ctor.IsNull() &&
!orig_implicit_ctor.IsImplicitConstructor()) {
// Not an implicit constructor, but a user declared one.
orig_implicit_ctor = Function::null();
}
const GrowableObjectArray& new_functions = GrowableObjectArray::Handle(
GrowableObjectArray::New(orig_len));
for (intptr_t i = 0; i < orig_len; i++) {
orig_func ^= orig_list.At(i);
member_name ^= orig_func.name();
func = patch.LookupFunction(member_name);
if (func.IsNull()) {
// Non-patched function is preserved, all patched functions are added in
// the loop below.
// However, an implicitly created constructor should not be preserved if
// the patch provides a constructor or a factory. Wait for now.
if (orig_func.raw() != orig_implicit_ctor.raw()) {
new_functions.Add(orig_func);
}
} else if (func.UserVisibleSignature() !=
orig_func.UserVisibleSignature()) {
// Compare user visible signatures to ignore different implicit parameters
// when patching a constructor with a factory.
*error = FormatError(*error, // No previous error.
Script::Handle(patch.script()), func.token_pos(),
"signature mismatch: '%s'", member_name.ToCString());
return false;
}
}
for (intptr_t i = 0; i < patch_len; i++) {
func ^= patch_list.At(i);
if (func.IsConstructor() || func.IsFactory()) {
// Do not preserve the original implicit constructor, if any.
orig_implicit_ctor = Function::null();
}
func.set_owner(patch_class);
new_functions.Add(func);
}
if (!orig_implicit_ctor.IsNull()) {
// Preserve the original implicit constructor.
new_functions.Add(orig_implicit_ctor);
}
Array& new_list = Array::Handle(Array::MakeArray(new_functions));
SetFunctions(new_list);
// Merge the two list of fields. Raise an error when duplicates are found or
// when a public field is being added.
orig_list = fields();
orig_len = orig_list.Length();
patch_list = patch.fields();
patch_len = patch_list.Length();
Field& field = Field::Handle();
Field& orig_field = Field::Handle();
new_list = Array::New(patch_len + orig_len);
for (intptr_t i = 0; i < patch_len; i++) {
field ^= patch_list.At(i);
field.set_owner(*this);
member_name = field.name();
// TODO(iposva): Verify non-public fields only.
// Verify no duplicate additions.
orig_field ^= LookupField(member_name);
if (!orig_field.IsNull()) {
*error = FormatError(*error, // No previous error.
Script::Handle(patch.script()), field.token_pos(),
"duplicate field: %s", member_name.ToCString());
return false;
}
new_list.SetAt(i, field);
}
for (intptr_t i = 0; i < orig_len; i++) {
field ^= orig_list.At(i);
new_list.SetAt(patch_len + i, field);
}
SetFields(new_list);
// The functions and fields in the patch class are no longer needed.
patch.SetFunctions(Object::empty_array());
patch.SetFields(Object::empty_array());
return true;
}
static RawPatchClass* MakeTempPatchClass(const Class& cls,
const String& expr) {
String& src = String::Handle(String::New("() => "));
src = String::Concat(src, expr);
src = String::Concat(src, Symbols::Semicolon());
Script& script = Script::Handle();
script = Script::New(Symbols::Empty(), src, RawScript::kSourceTag);
// In order to tokenize the source, we need to get the key to mangle
// private names from the library from which the object's class
// originates.
const Library& lib = Library::Handle(cls.library());
ASSERT(!lib.IsNull());
const String& lib_key = String::Handle(lib.private_key());
script.Tokenize(lib_key);
const String& src_class_name = String::Handle(Symbols::New(":internal"));
const Class& src_class = Class::Handle(
Class::New(src_class_name, script, Scanner::kDummyTokenIndex));
src_class.set_is_finalized();
src_class.set_library(lib);
return PatchClass::New(cls, src_class);
}
RawObject* Class::Evaluate(const String& expr) const {
const PatchClass& temp_class =
PatchClass::Handle(MakeTempPatchClass(*this, expr));
const String& eval_func_name = String::Handle(Symbols::New(":eval"));
const Function& eval_func =
Function::Handle(Function::New(eval_func_name,
RawFunction::kRegularFunction,
true, // Static.
false, // Not const.
false, // Not abstract.
false, // Not external.
temp_class,
0));
eval_func.set_result_type(Type::Handle(Type::DynamicType()));
eval_func.set_num_fixed_parameters(0);
eval_func.SetNumOptionalParameters(0, true);
eval_func.set_is_optimizable(false);
const Array& args = Array::Handle(Array::New(0));
const Object& result =
Object::Handle(DartEntry::InvokeFunction(eval_func, args));
return result.raw();
}
// Ensure that top level parsing of the class has been done.
RawError* Class::EnsureIsFinalized(Isolate* isolate) const {
// Finalized classes have already been parsed.
if (is_finalized()) {
return Error::null();
}
ASSERT(isolate != NULL);
const Error& error = Error::Handle(isolate, Compiler::CompileClass(*this));
if (!error.IsNull() && (isolate->long_jump_base() != NULL)) {
isolate->long_jump_base()->Jump(1, error);
UNREACHABLE();
}
return error.raw();
}
void Class::SetFields(const Array& value) const {
ASSERT(!value.IsNull());
#if defined(DEBUG)
// Verify that all the fields in the array have this class as owner.
Field& field = Field::Handle();
intptr_t len = value.Length();
for (intptr_t i = 0; i < len; i++) {
field ^= value.At(i);
ASSERT(field.owner() == raw());
}
#endif
// The value of static fields is already initialized to null.
StorePointer(&raw_ptr()->fields_, value.raw());
}
template <class FakeInstance>
RawClass* Class::New(intptr_t index) {
ASSERT(Object::class_class() != Class::null());
Class& result = Class::Handle();
{
RawObject* raw = Object::Allocate(Class::kClassId,
Class::InstanceSize(),
Heap::kOld);
NoGCScope no_gc;
result ^= raw;
}
FakeInstance fake;
ASSERT(fake.IsInstance());
result.set_handle_vtable(fake.vtable());
result.set_instance_size(FakeInstance::InstanceSize());
result.set_next_field_offset(FakeInstance::InstanceSize());
result.set_id(index);
result.raw_ptr()->state_bits_ = 0;
result.raw_ptr()->type_arguments_field_offset_in_words_ = kNoTypeArguments;
result.raw_ptr()->num_native_fields_ = 0;
result.raw_ptr()->token_pos_ = Scanner::kDummyTokenIndex;
result.InitEmptyFields();
Isolate::Current()->RegisterClass(result);
return result.raw();
}
RawClass* Class::New(const String& name,
const Script& script,
intptr_t token_pos) {
Class& result = Class::Handle(New<Instance>(kIllegalCid));
result.set_name(name);
result.set_script(script);
result.set_token_pos(token_pos);
return result.raw();
}
RawClass* Class::NewSignatureClass(const String& name,
const Function& signature_function,
const Script& script,
intptr_t token_pos) {
const Class& result = Class::Handle(New(name, script, token_pos));
// Instances of a signature class can only be closures.
result.set_instance_size(Closure::InstanceSize());
result.set_next_field_offset(Closure::InstanceSize());
// Signature classes extend the _FunctionImpl class.
result.set_super_type(Type::Handle(
Isolate::Current()->object_store()->function_impl_type()));
result.set_is_synthesized_class();
result.set_type_arguments_field_offset(Closure::type_arguments_offset());
if (!signature_function.IsNull()) {
result.PatchSignatureFunction(signature_function);
}
return result.raw();
}
void Class::PatchSignatureFunction(const Function& signature_function) const {
ASSERT(!signature_function.IsNull());
const Class& owner_class = Class::Handle(signature_function.Owner());
ASSERT(!owner_class.IsNull());
TypeArguments& type_parameters = TypeArguments::Handle();
// A signature class extends class Instance and is parameterized in the same
// way as the owner class of its non-static signature function.
// It is not type parameterized if its signature function is static.
// In case of a function type alias, the function owner is the alias class
// instead of the enclosing class.
if (!signature_function.is_static() &&
(owner_class.NumTypeParameters() > 0) &&
!signature_function.HasInstantiatedSignature()) {
type_parameters = owner_class.type_parameters();
}
set_signature_function(signature_function);
set_type_parameters(type_parameters);
if (owner_class.raw() == raw()) {
// This signature class is an alias, which cannot be the canonical
// signature class for this signature function.
ASSERT(!IsCanonicalSignatureClass());
} else if (signature_function.signature_class() == Object::null()) {
// Make this signature class the canonical signature class.
signature_function.set_signature_class(*this);
ASSERT(IsCanonicalSignatureClass());
}
set_is_prefinalized();
}
RawClass* Class::NewNativeWrapper(const Library& library,
const String& name,
int field_count) {
Class& cls = Class::Handle(library.LookupClass(name));
if (cls.IsNull()) {
cls = New(name, Script::Handle(), Scanner::kDummyTokenIndex);
cls.SetFields(Object::empty_array());
cls.SetFunctions(Object::empty_array());
// Set super class to Object.
cls.set_super_type(Type::Handle(Type::ObjectType()));
// Compute instance size. First word contains a pointer to a properly
// sized typed array once the first native field has been set.
intptr_t instance_size = sizeof(RawObject) + kWordSize;
cls.set_instance_size(RoundedAllocationSize(instance_size));
cls.set_next_field_offset(instance_size);
cls.set_num_native_fields(field_count);
cls.set_is_finalized();
cls.set_is_type_finalized();
library.AddClass(cls);
return cls.raw();
} else {
return Class::null();
}
}
RawClass* Class::NewStringClass(intptr_t class_id) {
intptr_t instance_size;
if (class_id == kOneByteStringCid) {
instance_size = OneByteString::InstanceSize();
} else if (class_id == kTwoByteStringCid) {
instance_size = TwoByteString::InstanceSize();
} else if (class_id == kExternalOneByteStringCid) {
instance_size = ExternalOneByteString::InstanceSize();
} else {
ASSERT(class_id == kExternalTwoByteStringCid);
instance_size = ExternalTwoByteString::InstanceSize();
}
Class& result = Class::Handle(New<String>(class_id));
result.set_instance_size(instance_size);
result.set_next_field_offset(instance_size);
result.set_is_prefinalized();
return result.raw();
}
RawClass* Class::NewTypedDataClass(intptr_t class_id) {
ASSERT(RawObject::IsTypedDataClassId(class_id));
intptr_t instance_size = TypedData::InstanceSize();
Class& result = Class::Handle(New<TypedData>(class_id));
result.set_instance_size(instance_size);
result.set_next_field_offset(instance_size);
result.set_is_prefinalized();
return result.raw();
}
RawClass* Class::NewTypedDataViewClass(intptr_t class_id) {
ASSERT(RawObject::IsTypedDataViewClassId(class_id));
Class& result = Class::Handle(New<Instance>(class_id));
result.set_instance_size(0);
result.set_next_field_offset(0);
return result.raw();
}
RawClass* Class::NewExternalTypedDataClass(intptr_t class_id) {
ASSERT(RawObject::IsExternalTypedDataClassId(class_id));
intptr_t instance_size = ExternalTypedData::InstanceSize();
Class& result = Class::Handle(New<ExternalTypedData>(class_id));
result.set_instance_size(instance_size);
result.set_next_field_offset(instance_size);
result.set_is_prefinalized();
return result.raw();
}
void Class::set_name(const String& value) const {
ASSERT(value.IsSymbol());
StorePointer(&raw_ptr()->name_, value.raw());
}
void Class::set_script(const Script& value) const {
StorePointer(&raw_ptr()->script_, value.raw());
}
void Class::set_token_pos(intptr_t token_pos) const {
ASSERT(token_pos >= 0);
raw_ptr()->token_pos_ = token_pos;
}
void Class::set_is_implemented() const {
set_state_bits(ImplementedBit::update(true, raw_ptr()->state_bits_));
}
void Class::set_is_abstract() const {
set_state_bits(AbstractBit::update(true, raw_ptr()->state_bits_));
}
void Class::set_is_type_finalized() const {
set_state_bits(TypeFinalizedBit::update(true, raw_ptr()->state_bits_));
}
void Class::set_is_patch() const {
set_state_bits(PatchBit::update(true, raw_ptr()->state_bits_));
}
void Class::set_is_synthesized_class() const {
set_state_bits(SynthesizedClassBit::update(true, raw_ptr()->state_bits_));
}
void Class::set_is_const() const {
set_state_bits(ConstBit::update(true, raw_ptr()->state_bits_));
}
void Class::set_is_mixin_typedef() const {
set_state_bits(MixinTypedefBit::update(true, raw_ptr()->state_bits_));
}
void Class::set_is_mixin_type_applied() const {
set_state_bits(MixinTypeAppliedBit::update(true, raw_ptr()->state_bits_));
}
void Class::set_is_finalized() const {
ASSERT(!is_finalized());
set_state_bits(ClassFinalizedBits::update(RawClass::kFinalized,
raw_ptr()->state_bits_));
}
void Class::set_is_prefinalized() const {
ASSERT(!is_finalized());
set_state_bits(ClassFinalizedBits::update(RawClass::kPreFinalized,
raw_ptr()->state_bits_));
}
void Class::set_is_marked_for_parsing() const {
set_state_bits(MarkedForParsingBit::update(true, raw_ptr()->state_bits_));
}
void Class::reset_is_marked_for_parsing() const {
set_state_bits(MarkedForParsingBit::update(false, raw_ptr()->state_bits_));
}
void Class::set_interfaces(const Array& value) const {
// Verification and resolving of interfaces occurs in finalizer.
ASSERT(!value.IsNull());
StorePointer(&raw_ptr()->interfaces_, value.raw());
}
void Class::set_mixin(const Type& value) const {
// Resolution and application of mixin type occurs in finalizer.
ASSERT(!value.IsNull());
StorePointer(&raw_ptr()->mixin_, value.raw());
}
bool Class::IsMixinApplication() const {
return mixin() != Type::null();
}
void Class::set_patch_class(const Class& cls) const {
ASSERT(patch_class() == Class::null());
StorePointer(&raw_ptr()->patch_class_, cls.raw());
}
void Class::AddDirectSubclass(const Class& subclass) const {
ASSERT(!subclass.IsNull());
ASSERT(subclass.SuperClass() == raw());
// Do not keep track of the direct subclasses of class Object.
ASSERT(!IsObjectClass());
GrowableObjectArray& direct_subclasses =
GrowableObjectArray::Handle(raw_ptr()->direct_subclasses_);
if (direct_subclasses.IsNull()) {
direct_subclasses = GrowableObjectArray::New(4, Heap::kOld);
StorePointer(&raw_ptr()->direct_subclasses_, direct_subclasses.raw());
}
#if defined(DEBUG)
// Verify that the same class is not added twice.
for (intptr_t i = 0; i < direct_subclasses.Length(); i++) {
ASSERT(direct_subclasses.At(i) != subclass.raw());
}
#endif
direct_subclasses.Add(subclass);
}
RawArray* Class::constants() const {
return raw_ptr()->constants_;
}
void Class::set_constants(const Array& value) const {
ASSERT(!value.IsNull());
StorePointer(&raw_ptr()->constants_, value.raw());
}
RawArray* Class::canonical_types() const {
return raw_ptr()->canonical_types_;
}
void Class::set_canonical_types(const Array& value) const {
ASSERT(!value.IsNull());
StorePointer(&raw_ptr()->canonical_types_, value.raw());
}
void Class::set_allocation_stub(const Code& value) const {
ASSERT(!value.IsNull());
ASSERT(raw_ptr()->allocation_stub_ == Code::null());
StorePointer(&raw_ptr()->allocation_stub_, value.raw());
}
bool Class::IsFunctionClass() const {
return raw() == Type::Handle(Type::Function()).type_class();
}
bool Class::IsCanonicalSignatureClass() const {
const Function& function = Function::Handle(signature_function());
return (!function.IsNull() && (function.signature_class() == raw()));
}
// If test_kind == kIsSubtypeOf, checks if type S is a subtype of type T.
// If test_kind == kIsMoreSpecificThan, checks if S is more specific than T.
// Type S is specified by this class parameterized with 'type_arguments', and
// type T by class 'other' parameterized with 'other_type_arguments'.
// This class and class 'other' do not need to be finalized, however, they must
// be resolved as well as their interfaces.
bool Class::TypeTest(
TypeTestKind test_kind,
const AbstractTypeArguments& type_arguments,
const Class& other,
const AbstractTypeArguments& other_type_arguments,
Error* bound_error) const {
ASSERT(!IsVoidClass());
// Check for DynamicType.
// Each occurrence of DynamicType in type T is interpreted as the dynamic
// type, a supertype of all types.
if (other.IsDynamicClass()) {
return true;
}
// In the case of a subtype test, each occurrence of DynamicType in type S is
// interpreted as the bottom type, a subtype of all types.
// However, DynamicType is not more specific than any type.
if (IsDynamicClass()) {
return test_kind == kIsSubtypeOf;
}
// Check for NullType, which is only a subtype of ObjectType, of DynamicType,
// or of itself, and which is more specific than any type.
if (IsNullClass()) {
// We already checked for other.IsDynamicClass() above.
return (test_kind == kIsMoreSpecificThan) ||
other.IsObjectClass() || other.IsNullClass();
}
// Check for ObjectType. Any type that is not NullType or DynamicType (already
// checked above), is more specific than ObjectType.
if (other.IsObjectClass()) {
return true;
}
// Check for reflexivity.
if (raw() == other.raw()) {
const intptr_t len = NumTypeArguments();
if (len == 0) {
return true;
}
// Since we do not truncate the type argument vector of a subclass (see
// below), we only check a prefix of the proper length.
// Check for covariance.
if (other_type_arguments.IsNull() || other_type_arguments.IsRaw(len)) {
return true;
}
if (type_arguments.IsNull() || type_arguments.IsRaw(len)) {
// Other type can't be more specific than this one because for that
// it would have to have all dynamic type arguments which is checked
// above.
return test_kind == kIsSubtypeOf;
}
return type_arguments.TypeTest(test_kind,
other_type_arguments,
len,
bound_error);
}
const bool other_is_function_class = other.IsFunctionClass();
if (other.IsSignatureClass() || other_is_function_class) {
const Function& other_fun = Function::Handle(other.signature_function());
if (IsSignatureClass()) {
if (other_is_function_class) {
return true;
}
// Check for two function types.
const Function& fun = Function::Handle(signature_function());
return fun.TypeTest(test_kind,
type_arguments,
other_fun,
other_type_arguments,
bound_error);
}
// Check if type S has a call() method of function type T.
Function& function =
Function::Handle(LookupDynamicFunction(Symbols::Call()));
if (function.IsNull()) {
// Walk up the super_class chain.
Class& cls = Class::Handle(SuperClass());
while (!cls.IsNull() && function.IsNull()) {
function = cls.LookupDynamicFunction(Symbols::Call());
cls = cls.SuperClass();
}
}
if (!function.IsNull()) {
if (other_is_function_class ||
function.TypeTest(test_kind,
type_arguments,
other_fun,
other_type_arguments,
bound_error)) {
return true;
}
}
}
// Check for 'direct super type' specified in the implements clause
// and check for transitivity at the same time.
Array& interfaces = Array::Handle(this->interfaces());
AbstractType& interface = AbstractType::Handle();
Class& interface_class = Class::Handle();
AbstractTypeArguments& interface_args = AbstractTypeArguments::Handle();
Error& args_bound_error = Error::Handle();
for (intptr_t i = 0; i < interfaces.Length(); i++) {
interface ^= interfaces.At(i);
if (!interface.IsFinalized()) {
// We may be checking bounds at finalization time. Skipping this
// unfinalized interface will postpone bound checking to run time.
continue;
}
interface_class = interface.type_class();
interface_args = interface.arguments();
if (!interface_args.IsNull() && !interface_args.IsInstantiated()) {
// This type class implements an interface that is parameterized with
// generic type(s), e.g. it implements List<T>.
// The uninstantiated type T must be instantiated using the type
// parameters of this type before performing the type test.
// The type arguments of this type that are referred to by the type
// parameters of the interface are at the end of the type vector,
// after the type arguments of the super type of this type.
// The index of the type parameters is adjusted upon finalization.
args_bound_error = Error::null();
interface_args = interface_args.InstantiateFrom(type_arguments,
&args_bound_error);
if (!args_bound_error.IsNull()) {
// Return the first bound error to the caller if it requests it.
if ((bound_error != NULL) && bound_error->IsNull()) {
*bound_error = args_bound_error.raw();
}
continue; // Another interface may work better.
}
}
if (interface_class.TypeTest(test_kind,
interface_args,
other,
other_type_arguments,
bound_error)) {
return true;
}
}
const Class& super_class = Class::Handle(SuperClass());
if (super_class.IsNull()) {
return false;
}
// Instead of truncating the type argument vector to the length of the super
// type argument vector, we make sure that the code works with a vector that
// is longer than necessary.
return super_class.TypeTest(test_kind,
type_arguments,
other,
other_type_arguments,
bound_error);
}
bool Class::IsTopLevel() const {
return Name() == Symbols::TopLevel().raw();
}
RawFunction* Class::LookupDynamicFunction(const String& name) const {
return LookupFunction(name, kInstance);
}
RawFunction* Class::LookupDynamicFunctionAllowPrivate(
const String& name) const {
return LookupFunctionAllowPrivate(name, kInstance);
}
RawFunction* Class::LookupStaticFunction(const String& name) const {
return LookupFunction(name, kStatic);
}
RawFunction* Class::LookupStaticFunctionAllowPrivate(const String& name) const {
return LookupFunctionAllowPrivate(name, kStatic);
}
RawFunction* Class::LookupConstructor(const String& name) const {
return LookupFunction(name, kConstructor);
}
RawFunction* Class::LookupConstructorAllowPrivate(const String& name) const {
return LookupFunctionAllowPrivate(name, kConstructor);
}
RawFunction* Class::LookupFactory(const String& name) const {
return LookupFunction(name, kFactory);
}
RawFunction* Class::LookupFunction(const String& name) const {
return LookupFunction(name, kAny);
}
RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const {
return LookupFunctionAllowPrivate(name, kAny);
}
// Returns true if 'prefix' and 'accessor_name' match 'name'.
static bool MatchesAccessorName(const String& name,
const char* prefix,
intptr_t prefix_length,
const String& accessor_name) {
intptr_t name_len = name.Length();
intptr_t accessor_name_len = accessor_name.Length();
if (name_len != (accessor_name_len + prefix_length)) {
return false;
}
for (intptr_t i = 0; i < prefix_length; i++) {
if (name.CharAt(i) != prefix[i]) {
return false;
}
}
for (intptr_t i = 0, j = prefix_length; i < accessor_name_len; i++, j++) {
if (name.CharAt(j) != accessor_name.CharAt(i)) {
return false;
}
}
return true;
}
RawFunction* Class::CheckFunctionType(const Function& func, intptr_t type) {
if (type == kInstance) {
if (func.IsDynamicFunction()) {
return func.raw();
}
} else if (type == kStatic) {
if (func.IsStaticFunction()) {
return func.raw();
}
} else if (type == kConstructor) {
if (func.IsConstructor()) {
ASSERT(!func.is_static());
return func.raw();
}
} else if (type == kFactory) {
if (func.IsFactory()) {
ASSERT(func.is_static());
return func.raw();
}
} else if (type == kAny) {
return func.raw();
}
return Function::null();
}
RawFunction* Class::LookupFunction(const String& name, intptr_t type) const {
Isolate* isolate = Isolate::Current();
if (EnsureIsFinalized(isolate) != Error::null()) {
return Function::null();
}
ReusableHandleScope reused_handles(isolate);
Array& funcs = reused_handles.ArrayHandle();
funcs ^= functions();
ASSERT(!funcs.IsNull());
Function& function = reused_handles.FunctionHandle();
const intptr_t len = funcs.Length();
if (name.IsSymbol()) {
// Quick Symbol compare.
NoGCScope no_gc;
for (intptr_t i = 0; i < len; i++) {
function ^= funcs.At(i);
if (function.name() == name.raw()) {
return CheckFunctionType(function, type);
}
}
} else {
String& function_name = reused_handles.StringHandle();
for (intptr_t i = 0; i < len; i++) {
function ^= funcs.At(i);
function_name ^= function.name();
if (function_name.Equals(name)) {
return CheckFunctionType(function, type);
}
}
}
// No function found.
return Function::null();
}
RawFunction* Class::LookupFunctionAllowPrivate(const String& name,
intptr_t type) const {
Isolate* isolate = Isolate::Current();