From 3481c5661a43d6bf2d1766fa8bb4e1dbc79025ff Mon Sep 17 00:00:00 2001 From: "sgjesse@google.com" Date: Thu, 9 Feb 2012 08:47:19 +0000 Subject: [PATCH] Decode the Dart message into a Dart_CMessage structure before calling the native port callback The native port callback is now passed the message as a decodes Dart_CMessage structure. The Dart_CMessage structure is allocated in a zone and the callback receiving it should expect the lifetime to be controlled by the caller. Added support for zones which do not require a current isolate. Changed the GrowableArray to support allocating in aprovided zone instead of the zone for the current isolate. R=turnidge@google.com, asiva@google.com BUG= TEST= Review URL: https://chromiumcodereview.appspot.com//9325022 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4068 260f80e4-7a28-3924-810f-c04153c831b5 --- runtime/include/dart_api.h | 105 +++++------ runtime/vm/dart.cc | 4 +- runtime/vm/dart_api_impl.cc | 10 +- runtime/vm/dart_api_impl.h | 10 ++ runtime/vm/dart_api_impl_test.cc | 28 +-- runtime/vm/dart_api_message.cc | 259 +++++++++++++++++++++++++++ runtime/vm/dart_api_message.h | 81 +++++++++ runtime/vm/dart_api_state.h | 50 +++++- runtime/vm/growable_array.h | 34 ++-- runtime/vm/native_message_handler.cc | 25 ++- runtime/vm/snapshot.cc | 236 ------------------------ runtime/vm/snapshot.h | 62 ------- runtime/vm/snapshot_test.cc | 33 ++-- runtime/vm/vm_sources.gypi | 2 + runtime/vm/zone.h | 7 + 15 files changed, 556 insertions(+), 390 deletions(-) create mode 100644 runtime/vm/dart_api_message.cc create mode 100644 runtime/vm/dart_api_message.h diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h index edac66ea979..4d8772fb7a5 100755 --- a/runtime/include/dart_api.h +++ b/runtime/include/dart_api.h @@ -535,16 +535,69 @@ DART_EXPORT bool Dart_HasLivePorts(); */ DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle object); +// --- Message sending/receiving from native code ---- + +/** + * A Dart_CObject is used for representing Dart objects as native C + * data outside the Dart heap. These objects are totally detached from + * the Dart heap. Only a subset of the Dart objects have a + * representation as a Dart_CObject. + */ +struct Dart_CObject { + enum Type { + kNull = 0, + kBool, + kInt32, + kDouble, + kString, + kArray, + kNumberOfTypes + }; + Type type; + union { + bool as_bool; + int32_t as_int32; + double as_double; + char* as_string; + struct { + int length; + Dart_CObject** values; + } as_array; + } value; +}; + +/** + * Posts a message on some port. The message will contain the + * Dart_CObject object graph rooted in 'message'. + * + * While the message is being sent the state of the graph of + * Dart_CObject structures rooted in 'message' should not be accessed, + * as the message generation will make temporary modifications to the + * data. When the message has been sent the graph will be fully + * restored. + * + * \param port_id The destination port. + * \param message The message to send. + * + * \return True if the message was posted. + */ +DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message); + /** * A native message handler. * * This handler is associated with a native port by calling * Dart_NewNativePort. + * + * The message received is decoded into the message structure. The + * lifetime of the message data is controlled by the caller. All the + * data references from the message are allocated by the caller and + * will be reclaimed when returning to it. */ + typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id, Dart_Port reply_port_id, - uint8_t* data); -// TODO(turnidge): Make this function take more appropriate arguments. + Dart_CObject* message); /** * Creates a new native port. When messages are received on this @@ -1414,52 +1467,4 @@ DART_EXPORT Dart_Handle Dart_SetNativeResolver( DART_EXPORT void Dart_InitPprofSupport(); DART_EXPORT void Dart_GetPprofSymbolInfo(void** buffer, int* buffer_size); -// --- Message sending/receiving from native code ---- - -/** - * A Dart_CObject is used for representing Dart objects as native C - * data outside the Dart heap. These objects are totally detached from - * the Dart heap. Only a subset of the Dart objects have a - * representation as a Dart_CObject. - */ -struct Dart_CObject { - enum Type { - kNull = 0, - kBool, - kInt32, - kDouble, - kString, - kArray, - kNumberOfTypes - }; - Type type; - union { - bool as_bool; - int32_t as_int32; - double as_double; - char* as_string; - struct { - int length; - Dart_CObject** values; - } as_array; - } value; -}; - -/** - * Posts a message on some port. The message will contain the - * Dart_CObject object graph rooted in 'message'. - * - * While the message is being sent the state of the graph of - * Dart_CObject structures rooted in 'message' should not be accessed, - * as the message generation will make temporary modifications to the - * data. When the message has been sent the graph will be fully - * restored. - * - * \param port_id The destination port. - * \param message The message to send. - * - * \return True if the message was posted. - */ -DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message); - #endif // INCLUDE_DART_API_H_ diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index b54564b23b1..ecbfa2d3e85 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -1,10 +1,11 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file +// 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/dart.h" #include "vm/code_index_table.h" +#include "vm/dart_api_state.h" #include "vm/flags.h" #include "vm/freelist.h" #include "vm/handles.h" @@ -34,6 +35,7 @@ bool Dart::InitOnce(Dart_IsolateCreateCallback create, Isolate::InitOnce(); PortMap::InitOnce(); FreeListElement::InitOnce(); + Api::InitOnce(); // Create the VM isolate and finish the VM initialization. { ASSERT(vm_isolate_ == NULL); diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index b282bf2fd91..e7d538c024a 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -28,6 +28,8 @@ namespace dart { +ThreadLocalKey Api::api_native_key_ = Thread::kUnsetThreadLocalKey; + const char* CanonicalFunction(const char* func) { if (strncmp(func, "dart::", 6) == 0) { return func + 6; @@ -237,6 +239,13 @@ uword Api::Reallocate(uword ptr, intptr_t old_size, intptr_t new_size) { } +void Api::InitOnce() { + ASSERT(api_native_key_ == Thread::kUnsetThreadLocalKey); + api_native_key_ = Thread::CreateThreadLocal(); + ASSERT(api_native_key_ != Thread::kUnsetThreadLocalKey); +} + + // --- Handles --- @@ -2437,5 +2446,4 @@ DART_EXPORT void Dart_GetPprofSymbolInfo(void** buffer, int* buffer_size) { } } - } // namespace dart diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h index e41e96f592a..4cf06683b87 100644 --- a/runtime/vm/dart_api_impl.h +++ b/runtime/vm/dart_api_impl.h @@ -121,6 +121,16 @@ class Api : AllStatic { // Reallocates space in the local zone. static uword Reallocate(uword ptr, intptr_t old_size, intptr_t new_size); + + // Performs one-time initialization needed by the API. + static void InitOnce(); + + private: + // Thread local key used by the API. Currently holds the current + // ApiNativeScope if any. + static ThreadLocalKey api_native_key_; + + friend class ApiNativeScope; }; class IsolateSaver { diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc index b28aed7ff72..c1b105b6d62 100644 --- a/runtime/vm/dart_api_impl_test.cc +++ b/runtime/vm/dart_api_impl_test.cc @@ -2890,23 +2890,31 @@ TEST_CASE(ImportLibrary5) { void NewNativePort_send123(Dart_Port dest_port_id, Dart_Port reply_port_id, - uint8_t* data) { + Dart_CObject *message) { + // Gets a null message. + EXPECT_NOTNULL(message); + EXPECT_EQ(Dart_CObject::kNull, message->type); + // Post integer value. - Dart_CObject object; - object.type = Dart_CObject::kInt32; - object.value.as_int32 = 123; - Dart_PostCObject(reply_port_id, &object); + Dart_CObject response; + response.type = Dart_CObject::kInt32; + response.value.as_int32 = 123; + Dart_PostCObject(reply_port_id, &response); } void NewNativePort_send321(Dart_Port dest_port_id, Dart_Port reply_port_id, - uint8_t* data) { + Dart_CObject* message) { + // Gets a null message. + EXPECT_NOTNULL(message); + EXPECT_EQ(Dart_CObject::kNull, message->type); + // Post integer value. - Dart_CObject object; - object.type = Dart_CObject::kInt32; - object.value.as_int32 = 321; - Dart_PostCObject(reply_port_id, &object); + Dart_CObject response; + response.type = Dart_CObject::kInt32; + response.value.as_int32 = 321; + Dart_PostCObject(reply_port_id, &response); } diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc new file mode 100644 index 00000000000..cef65c67e1b --- /dev/null +++ b/runtime/vm/dart_api_message.cc @@ -0,0 +1,259 @@ +// 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/dart_api_message.h" +#include "vm/object.h" +#include "vm/object_store.h" + +namespace dart { + +// TODO(sgjesse): When the external message format is done these +// duplicate constants from snapshot.cc should be removed. +enum { + kInstanceId = ObjectStore::kMaxId, + kMaxPredefinedObjectIds, +}; +static const int kNumInitialReferences = 4; + +ApiMessageReader::ApiMessageReader(const uint8_t* buffer, + intptr_t length, + ReAlloc alloc) + : BaseReader(buffer, length), + alloc_(alloc), + backward_references_(kNumInitialReferences) { + Init(); +} + + +void ApiMessageReader::Init() { + // Initialize marker objects used to handle Lists. + // TODO(sjesse): Remove this when message serialization format is + // updated. + memset(&type_arguments_marker, 0, sizeof(type_arguments_marker)); + memset(&dynamic_type_marker, 0, sizeof(dynamic_type_marker)); + type_arguments_marker.type = + static_cast(Dart_CObject_Internal::kTypeArguments); + dynamic_type_marker.type = + static_cast(Dart_CObject_Internal::kDynamicType); +} + + +Dart_CObject* ApiMessageReader::ReadMessage() { + // Read the object out of the message. + return ReadObject(); +} + + +intptr_t ApiMessageReader::LookupInternalClass(intptr_t class_header) { + SerializedHeaderType header_type = SerializedHeaderTag::decode(class_header); + ASSERT(header_type == kObjectId); + intptr_t header_value = SerializedHeaderData::decode(class_header); + return header_value; +} + + +Dart_CObject* ApiMessageReader::AllocateDartCObject(Dart_CObject::Type type) { + Dart_CObject* value = + reinterpret_cast(alloc_(NULL, 0, sizeof(Dart_CObject))); + value->type = type; + return value; +} + + +Dart_CObject* ApiMessageReader::AllocateDartCObjectNull() { + return AllocateDartCObject(Dart_CObject::kNull); +} + + +Dart_CObject* ApiMessageReader::AllocateDartCObjectBool(bool val) { + Dart_CObject* value = AllocateDartCObject(Dart_CObject::kBool); + value->value.as_bool = val; + return value; +} + + +Dart_CObject* ApiMessageReader::AllocateDartCObjectInt32(int32_t val) { + Dart_CObject* value = AllocateDartCObject(Dart_CObject::kInt32); + value->value.as_int32 = val; + return value; +} + + +Dart_CObject* ApiMessageReader::AllocateDartCObjectDouble(double val) { + Dart_CObject* value = AllocateDartCObject(Dart_CObject::kDouble); + value->value.as_double = val; + return value; +} + + +Dart_CObject* ApiMessageReader::AllocateDartCObjectString(intptr_t length) { + // Allocate a Dart_CObject structure followed by an array of chars + // for the string content. The pointer to the string content is set + // up to this area. + Dart_CObject* value = + reinterpret_cast( + alloc_(NULL, 0, sizeof(Dart_CObject) + length + 1)); + value->value.as_string = reinterpret_cast(value) + sizeof(*value); + value->type = Dart_CObject::kString; + return value; +} + + +Dart_CObject* ApiMessageReader::AllocateDartCObjectArray(intptr_t length) { + // Allocate a Dart_CObject structure followed by an array of + // pointers to Dart_CObject structures. The pointer to the array + // content is set up to this area. + Dart_CObject* value = + reinterpret_cast( + alloc_(NULL, 0, sizeof(Dart_CObject) + length * sizeof(value))); + value->type = Dart_CObject::kArray; + value->value.as_array.length = length; + if (length > 0) { + value->value.as_array.values = reinterpret_cast(value + 1); + } else { + value->value.as_array.values = NULL; + } + return value; +} + + +Dart_CObject* ApiMessageReader::ReadInlinedObject(intptr_t object_id) { + // Read the class header information and lookup the class. + intptr_t class_header = ReadIntptrValue(); + intptr_t tags = ReadIntptrValue(); + USE(tags); + intptr_t class_id; + + // Reading of regular dart instances is not supported. + if (SerializedHeaderData::decode(class_header) == kInstanceId) { + return NULL; + } + + ASSERT((class_header & kSmiTagMask) != 0); + class_id = LookupInternalClass(class_header); + switch (class_id) { + case Object::kClassClass: { + return NULL; + } + case Object::kTypeArgumentsClass: { + // TODO(sjesse): Remove this when message serialization format is + // updated (currently length is leaked). + AddBackwardReference(object_id, NULL); + Dart_CObject* length = ReadObject(); + ASSERT(length->type == Dart_CObject::kInt32); + for (int i = 0; i < length->value.as_int32; i++) { + Dart_CObject* type = ReadObject(); + if (type != &dynamic_type_marker) return NULL; + } + return &type_arguments_marker; + break; + } + case ObjectStore::kArrayClass: { + intptr_t len = ReadSmiValue(); + Dart_CObject* value = AllocateDartCObjectArray(len); + AddBackwardReference(object_id, value); + // Skip type arguments. + // TODO(sjesse): Remove this when message serialization format is + // updated (currently type_arguments is leaked). + Dart_CObject* type_arguments = ReadObject(); + if (type_arguments != &type_arguments_marker && + type_arguments->type != Dart_CObject::kNull) { + return NULL; + } + for (int i = 0; i < len; i++) { + value->value.as_array.values[i] = ReadObject(); + } + return value; + break; + } + case ObjectStore::kDoubleClass: { + // Read the double value for the object. + Dart_CObject* object = AllocateDartCObjectDouble(Read()); + AddBackwardReference(object_id, object); + return object; + break; + } + case ObjectStore::kOneByteStringClass: { + intptr_t len = ReadSmiValue(); + intptr_t hash = ReadSmiValue(); + USE(hash); + Dart_CObject* object = AllocateDartCObjectString(len); + AddBackwardReference(object_id, object); + char* p = object->value.as_string; + for (intptr_t i = 0; i < len; i++) { + *p = Read(); + p++; + } + *p = '\0'; + return object; + break; + } + case ObjectStore::kTwoByteStringClass: + // Two byte strings not supported. + return NULL; + break; + case ObjectStore::kFourByteStringClass: + // Four byte strings not supported. + return NULL; + break; + default: + // Everything else not supported. + return NULL; + } +} + + +Dart_CObject* ApiMessageReader::ReadIndexedObject(intptr_t object_id) { + if (object_id == Object::kNullObject) { + return AllocateDartCObjectNull(); + } else if (object_id == ObjectStore::kTrueValue) { + return AllocateDartCObjectBool(true); + } else if (object_id == ObjectStore::kFalseValue) { + return AllocateDartCObjectBool(false); + } else if (object_id == ObjectStore::kDynamicType || + object_id == ObjectStore::kDoubleInterface || + object_id == ObjectStore::kIntInterface || + object_id == ObjectStore::kBoolInterface || + object_id == ObjectStore::kStringInterface) { + // Always return dynamic type (this is only a marker). + return &dynamic_type_marker; + } else { + intptr_t index = object_id - kMaxPredefinedObjectIds; + ASSERT(index < backward_references_.length()); + ASSERT(backward_references_[index] != NULL); + return backward_references_[index]; + } + return NULL; +} + + +Dart_CObject* ApiMessageReader::ReadObjectImpl(intptr_t header) { + SerializedHeaderType header_type = SerializedHeaderTag::decode(header); + intptr_t header_value = SerializedHeaderData::decode(header); + + if (header_type == kObjectId) { + return ReadIndexedObject(header_value); + } + ASSERT(header_type == kInlined); + return ReadInlinedObject(header_value); +} + + +Dart_CObject* ApiMessageReader::ReadObject() { + int64_t value = Read(); + if ((value & kSmiTagMask) == 0) { + Dart_CObject* dart_value = AllocateDartCObjectInt32(value >> kSmiTagShift); + return dart_value; + } + ASSERT((value <= kIntptrMax) && (value >= kIntptrMin)); + return ReadObjectImpl(value); +} + + +void ApiMessageReader::AddBackwardReference(intptr_t id, Dart_CObject* obj) { + ASSERT((id - kMaxPredefinedObjectIds) == backward_references_.length()); + backward_references_.Add(obj); +} + +} // namespace dart diff --git a/runtime/vm/dart_api_message.h b/runtime/vm/dart_api_message.h new file mode 100644 index 00000000000..76e29b4436d --- /dev/null +++ b/runtime/vm/dart_api_message.h @@ -0,0 +1,81 @@ +// 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. + +#ifndef VM_DART_API_MESSAGE_H_ +#define VM_DART_API_MESSAGE_H_ + +#include "vm/dart_api_state.h" +#include "vm/snapshot.h" + +namespace dart { + +// Use this C structure for reading internal objects in the serialized +// data. These are objects that we need to process in order to +// generate the Dart_CObject graph but that we don't want to expose in +// that graph. +// TODO(sjesse): Remove this when message serialization format is +// updated. +struct Dart_CObject_Internal : public Dart_CObject { + enum Type { + kTypeArguments = Dart_CObject::kNumberOfTypes, + kDynamicType, + }; +}; + + +// Reads a message snapshot into a C structure. +class ApiMessageReader : public BaseReader { + public: + ApiMessageReader(const uint8_t* buffer, intptr_t length, ReAlloc alloc); + ~ApiMessageReader() { } + + Dart_CObject* ReadMessage(); + + private: + // Allocates a Dart_CObject object. + Dart_CObject* AllocateDartCObject(); + // Allocates a Dart_CObject object with the specified type. + Dart_CObject* AllocateDartCObject(Dart_CObject::Type type); + // Allocates a Dart_CObject object for the null object. + Dart_CObject* AllocateDartCObjectNull(); + // Allocates a Dart_CObject object for a boolean object. + Dart_CObject* AllocateDartCObjectBool(bool value); + // Allocates a Dart_CObject object for for a 32-bit integer. + Dart_CObject* AllocateDartCObjectInt32(int32_t value); + // Allocates a Dart_CObject object for a double. + Dart_CObject* AllocateDartCObjectDouble(double value); + // Allocates a Dart_CObject object for string data. + Dart_CObject* AllocateDartCObjectString(intptr_t length); + // Allocates a C array of Dart_CObject objects. + Dart_CObject* AllocateDartCObjectArray(intptr_t length); + + void Init(); + + intptr_t LookupInternalClass(intptr_t class_header); + Dart_CObject* ReadInlinedObject(intptr_t object_id); + Dart_CObject* ReadObjectImpl(intptr_t header); + Dart_CObject* ReadIndexedObject(intptr_t object_id); + Dart_CObject* ReadObject(); + + // Add object to backward references. + void AddBackwardReference(intptr_t id, Dart_CObject* obj); + + Dart_CObject_Internal* AsInternal(Dart_CObject* object) { + ASSERT(object->type >= Dart_CObject::kNumberOfTypes); + return reinterpret_cast(object); + } + + // Allocation of the structures for the decoded message happens + // either in the supplied zone or using the supplied allocation + // function. + ReAlloc alloc_; + ApiGrowableArray backward_references_; + + Dart_CObject type_arguments_marker; + Dart_CObject dynamic_type_marker; +}; + +} // namespace dart + +#endif // VM_DART_API_MESSAGE_H_ diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h index 9badcc4fb94..de4fd9947c3 100644 --- a/runtime/vm/dart_api_state.h +++ b/runtime/vm/dart_api_state.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file +// 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. @@ -7,8 +7,10 @@ #include "include/dart_api.h" +#include "platform/thread.h" #include "vm/dart_api_impl.h" #include "vm/flags.h" +#include "vm/growable_array.h" #include "vm/handles.h" #include "vm/object.h" #include "vm/os.h" @@ -46,8 +48,11 @@ class ApiZone { intptr_t SizeInBytes() const { return zone_.SizeInBytes(); } private: + BaseZone* GetBaseZone() { return &zone_; } + BaseZone zone_; + template friend class ApiGrowableArray; DISALLOW_COPY_AND_ASSIGN(ApiZone); }; @@ -507,6 +512,49 @@ class ApiState { DISALLOW_COPY_AND_ASSIGN(ApiState); }; + +class ApiNativeScope { + public: + ApiNativeScope() { + // Currently no support for nesting native scopes. + ASSERT(Current() == NULL); + Thread::SetThreadLocal(Api::api_native_key_, reinterpret_cast(this)); + } + + ~ApiNativeScope() { + ASSERT(Current() == this); + Thread::SetThreadLocal(Api::api_native_key_, NULL); + } + + static inline ApiNativeScope* Current() { + return reinterpret_cast( + Thread::GetThreadLocal(Api::api_native_key_)); + } + + ApiZone* zone() { return &zone_; } + + private: + ApiZone zone_; +}; + + +// Api growable arrays use a zone for allocation. The constructor +// picks the zone from the current isolate if in an isolate +// environment. When outside an isolate environment it picks the zone +// from the current native scope. +template +class ApiGrowableArray : public BaseGrowableArray { + public: + explicit ApiGrowableArray(int initial_capacity) + : BaseGrowableArray( + initial_capacity, + ApiNativeScope::Current()->zone()->GetBaseZone()) {} + ApiGrowableArray() + : BaseGrowableArray( + ApiNativeScope::Current()->zone()->GetBaseZone()) {} +}; + + } // namespace dart #endif // VM_DART_API_STATE_H_ diff --git a/runtime/vm/growable_array.h b/runtime/vm/growable_array.h index 692da64a670..1223d719beb 100644 --- a/runtime/vm/growable_array.h +++ b/runtime/vm/growable_array.h @@ -18,15 +18,14 @@ namespace dart { template class BaseGrowableArray : public B { public: - BaseGrowableArray() : length_(0), capacity_(0), data_(NULL), zone_(NULL) { - ASSERT(Isolate::Current() != NULL); - zone_ = Isolate::Current()->current_zone(); + explicit BaseGrowableArray(BaseZone* zone) + : length_(0), capacity_(0), data_(NULL), zone_(zone) { + ASSERT(zone_ != NULL); } - explicit BaseGrowableArray(int initial_capacity) - : length_(0), capacity_(0), data_(NULL), zone_(NULL) { - ASSERT(Isolate::Current() != NULL); - zone_ = Isolate::Current()->current_zone(); + BaseGrowableArray(int initial_capacity, BaseZone* zone) + : length_(0), capacity_(0), data_(NULL), zone_(zone) { + ASSERT(zone_ != NULL); if (initial_capacity > 0) { capacity_ = Utils::RoundUpToPowerOfTwo(initial_capacity); data_ = reinterpret_cast(zone_->Allocate(capacity_ * sizeof(T))); @@ -76,7 +75,7 @@ class BaseGrowableArray : public B { int length_; int capacity_; T* data_; - Zone* zone_; // Zone in which we are allocating the array. + BaseZone* zone_; // Zone in which we are allocating the array. void Resize(int new_length); @@ -95,9 +94,6 @@ inline void BaseGrowableArray::Sort( template void BaseGrowableArray::Resize(int new_length) { if (new_length > capacity_) { - ASSERT(Isolate::Current() != NULL); - // Check that we allocating in the array's zone. - ASSERT(zone_ == Isolate::Current()->current_zone()); int new_capacity = Utils::RoundUpToPowerOfTwo(new_length); T* new_data = reinterpret_cast( zone_->Reallocate(reinterpret_cast(data_), @@ -115,8 +111,12 @@ template class GrowableArray : public BaseGrowableArray { public: explicit GrowableArray(int initial_capacity) - : BaseGrowableArray(initial_capacity) {} - GrowableArray() : BaseGrowableArray() {} + : BaseGrowableArray( + initial_capacity, + Isolate::Current()->current_zone()->GetBaseZone()) {} + GrowableArray() + : BaseGrowableArray( + Isolate::Current()->current_zone()->GetBaseZone()) {} }; @@ -124,8 +124,12 @@ template class ZoneGrowableArray : public BaseGrowableArray { public: explicit ZoneGrowableArray(int initial_capacity) - : BaseGrowableArray(initial_capacity) {} - ZoneGrowableArray() : BaseGrowableArray() {} + : BaseGrowableArray( + initial_capacity, + Isolate::Current()->current_zone()->GetBaseZone()) {} + ZoneGrowableArray() : + BaseGrowableArray( + Isolate::Current()->current_zone()->GetBaseZone()) {} }; } // namespace dart diff --git a/runtime/vm/native_message_handler.cc b/runtime/vm/native_message_handler.cc index ebc7121c848..8f47e7ff748 100644 --- a/runtime/vm/native_message_handler.cc +++ b/runtime/vm/native_message_handler.cc @@ -4,8 +4,10 @@ #include "vm/native_message_handler.h" +#include "vm/dart_api_message.h" #include "vm/isolate.h" #include "vm/message.h" +#include "vm/snapshot.h" #include "vm/thread.h" namespace dart { @@ -31,6 +33,14 @@ void NativeMessageHandler::CheckAccess() { #endif +static uint8_t* zone_allocator( + uint8_t* ptr, intptr_t old_size, intptr_t new_size) { + ApiZone* zone = ApiNativeScope::Current()->zone(); + return reinterpret_cast( + zone->Reallocate(reinterpret_cast(ptr), old_size, new_size)); +} + + static void RunWorker(uword parameter) { NativeMessageHandler* handler = reinterpret_cast(parameter); @@ -47,12 +57,19 @@ static void RunWorker(uword parameter) { // dispatched to special vm code. Implement. UNIMPLEMENTED(); } - // TODO(sgjesse): Once CMessageReader::ReadObject is committed, - // use that here and pass the resulting data object to the - // handler instead. + // Enter a native scope for handling the message. This will create a + // zone for allocating the objects for decoding the message. + ApiNativeScope scope; + + int32_t length = reinterpret_cast( + message->data())[Snapshot::kLengthIndex]; + ApiMessageReader reader(message->data() + Snapshot::kHeaderSize, + length, + zone_allocator); + Dart_CObject* object = reader.ReadMessage(); (*handler->func())(message->dest_port(), message->reply_port(), - message->data()); + object); delete message; } } diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc index ee4fb30dd67..016465ab743 100644 --- a/runtime/vm/snapshot.cc +++ b/runtime/vm/snapshot.cc @@ -437,242 +437,6 @@ RawObject* SnapshotReader::ReadInlinedObject(intptr_t object_id) { } -CMessageReader::CMessageReader(const uint8_t* buffer, - intptr_t length, - ReAlloc alloc) - : BaseReader(buffer, length), - alloc_(alloc), - backward_references_(kNumInitialReferences) { - // Initialize marker objects used to handle Lists. - // TODO(sjesse): Remove this when message serialization format is - // updated. - memset(&type_arguments_marker, 0, sizeof(type_arguments_marker)); - memset(&dynamic_type_marker, 0, sizeof(dynamic_type_marker)); - type_arguments_marker.type = - static_cast(Dart_CObject_Internal::kTypeArguments); - dynamic_type_marker.type = - static_cast(Dart_CObject_Internal::kDynamicType); -} - - -Dart_CObject* CMessageReader::ReadMessage() { - // Read the object out of the message. - return ReadObject(); -} - -intptr_t CMessageReader::LookupInternalClass(intptr_t class_header) { - SerializedHeaderType header_type = SerializedHeaderTag::decode(class_header); - ASSERT(header_type == kObjectId); - intptr_t header_value = SerializedHeaderData::decode(class_header); - return header_value; -} - - -Dart_CObject* CMessageReader::AllocateDartCObject(Dart_CObject::Type type) { - Dart_CObject* value = - reinterpret_cast( - alloc_(NULL, 0, sizeof(Dart_CObject))); - value->type = type; - return value; -} - - -Dart_CObject* CMessageReader::AllocateDartCObjectNull() { - return AllocateDartCObject(Dart_CObject::kNull); -} - - -Dart_CObject* CMessageReader::AllocateDartCObjectBool(bool val) { - Dart_CObject* value = AllocateDartCObject(Dart_CObject::kBool); - value->value.as_bool = val; - return value; -} - - -Dart_CObject* CMessageReader::AllocateDartCObjectInt32(int32_t val) { - Dart_CObject* value = AllocateDartCObject(Dart_CObject::kInt32); - value->value.as_int32 = val; - return value; -} - - -Dart_CObject* CMessageReader::AllocateDartCObjectDouble(double val) { - Dart_CObject* value = AllocateDartCObject(Dart_CObject::kDouble); - value->value.as_double = val; - return value; -} - - -Dart_CObject* CMessageReader::AllocateDartCObjectString(intptr_t length) { - // Allocate a Dart_CObject structure followed by an array of chars - // for the string content. The pointer to the string content is set - // up to this area. - Dart_CObject* value = - reinterpret_cast( - alloc_(NULL, 0, sizeof(Dart_CObject) + length + 1)); - value->value.as_string = reinterpret_cast(value) + sizeof(*value); - value->type = Dart_CObject::kString; - return value; -} - - -Dart_CObject* CMessageReader::AllocateDartCObjectArray(intptr_t length) { - // Allocate a Dart_CObject structure followed by an array of - // pointers to Dart_CObject structures. The pointer to the array - // content is set up to this area. - Dart_CObject* value = - reinterpret_cast( - alloc_(NULL, 0, sizeof(Dart_CObject) + length * sizeof(value))); - value->type = Dart_CObject::kArray; - value->value.as_array.length = length; - if (length > 0) { - value->value.as_array.values = reinterpret_cast(value + 1); - } else { - value->value.as_array.values = NULL; - } - return value; -} - - -Dart_CObject* CMessageReader::ReadInlinedObject(intptr_t object_id) { - // Read the class header information and lookup the class. - intptr_t class_header = ReadIntptrValue(); - intptr_t tags = ReadIntptrValue(); - USE(tags); - intptr_t class_id; - - // Reading of regular dart instances is not supported. - if (SerializedHeaderData::decode(class_header) == kInstanceId) { - return NULL; - } - - ASSERT((class_header & kSmiTagMask) != 0); - class_id = LookupInternalClass(class_header); - switch (class_id) { - case Object::kClassClass: { - return NULL; - } - case Object::kTypeArgumentsClass: { - // TODO(sjesse): Remove this when message serialization format is - // updated (currently length is leaked). - AddBackwardReference(object_id, NULL); - Dart_CObject* length = ReadObject(); - ASSERT(length->type == Dart_CObject::kInt32); - for (int i = 0; i < length->value.as_int32; i++) { - Dart_CObject* type = ReadObject(); - if (type != &dynamic_type_marker) return NULL; - } - return &type_arguments_marker; - break; - } - case ObjectStore::kArrayClass: { - intptr_t len = ReadSmiValue(); - Dart_CObject* value = AllocateDartCObjectArray(len); - AddBackwardReference(object_id, value); - // Skip type arguments. - // TODO(sjesse): Remove this when message serialization format is - // updated (currently type_arguments is leaked). - Dart_CObject* type_arguments = ReadObject(); - if (type_arguments != &type_arguments_marker && - type_arguments->type != Dart_CObject::kNull) { - return NULL; - } - for (int i = 0; i < len; i++) { - value->value.as_array.values[i] = ReadObject(); - } - return value; - break; - } - case ObjectStore::kDoubleClass: { - // Read the double value for the object. - Dart_CObject* object = AllocateDartCObjectDouble(Read()); - AddBackwardReference(object_id, object); - return object; - break; - } - case ObjectStore::kOneByteStringClass: { - intptr_t len = ReadSmiValue(); - intptr_t hash = ReadSmiValue(); - USE(hash); - Dart_CObject* object = AllocateDartCObjectString(len); - AddBackwardReference(object_id, object); - char* p = object->value.as_string; - for (intptr_t i = 0; i < len; i++) { - *p = Read(); - p++; - } - *p = '\0'; - return object; - break; - } - case ObjectStore::kTwoByteStringClass: - // Two byte strings not supported. - return NULL; - break; - case ObjectStore::kFourByteStringClass: - // Four byte strings not supported. - return NULL; - break; - default: - // Everything else not supported. - return NULL; - } -} - - -Dart_CObject* CMessageReader::ReadIndexedObject(intptr_t object_id) { - if (object_id == Object::kNullObject) { - return AllocateDartCObjectNull(); - } else if (object_id == ObjectStore::kTrueValue) { - return AllocateDartCObjectBool(true); - } else if (object_id == ObjectStore::kFalseValue) { - return AllocateDartCObjectBool(false); - } else if (object_id == ObjectStore::kDynamicType || - object_id == ObjectStore::kDoubleInterface || - object_id == ObjectStore::kIntInterface || - object_id == ObjectStore::kBoolInterface || - object_id == ObjectStore::kStringInterface) { - // Always return dynamic type (this is only a marker). - return &dynamic_type_marker; - } else { - intptr_t index = object_id - kMaxPredefinedObjectIds; - ASSERT(index < backward_references_.length()); - ASSERT(backward_references_[index] != NULL); - return backward_references_[index]; - } - return NULL; -} - - -Dart_CObject* CMessageReader::ReadObjectImpl(intptr_t header) { - SerializedHeaderType header_type = SerializedHeaderTag::decode(header); - intptr_t header_value = SerializedHeaderData::decode(header); - - if (header_type == kObjectId) { - return ReadIndexedObject(header_value); - } - ASSERT(header_type == kInlined); - return ReadInlinedObject(header_value); -} - - -Dart_CObject* CMessageReader::ReadObject() { - int64_t value = Read(); - if ((value & kSmiTagMask) == 0) { - Dart_CObject* dart_value = AllocateDartCObjectInt32(value >> kSmiTagShift); - return dart_value; - } - ASSERT((value <= kIntptrMax) && (value >= kIntptrMin)); - return ReadObjectImpl(value); -} - - -void CMessageReader::AddBackwardReference(intptr_t id, Dart_CObject* obj) { - ASSERT((id - kMaxPredefinedObjectIds) == backward_references_.length()); - backward_references_.Add(obj); -} - - void MessageWriter::WriteMessage(intptr_t field_count, intptr_t *data) { // Write out the serialization header value for this object. WriteSerializationMarker(kInlined, kMaxPredefinedObjectIds); diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h index 29de83f0eab..a9464d67ae8 100644 --- a/runtime/vm/snapshot.h +++ b/runtime/vm/snapshot.h @@ -404,68 +404,6 @@ class SnapshotReader : public BaseReader { }; -// Use this C structure for reading internal objects in the serialized -// data. These are objects that we need to process in order to -// generate the Dart_CObject graph but that we don't want to expose in -// that graph. -// TODO(sjesse): Remove this when message serialization format is -// updated. -struct Dart_CObject_Internal : public Dart_CObject { - enum Type { - kTypeArguments = Dart_CObject::kNumberOfTypes, - kDynamicType, - }; -}; - - -// Reads a message snapshot into C structure. -class CMessageReader : public BaseReader { - public: - CMessageReader(const uint8_t* buffer, intptr_t length, ReAlloc alloc); - ~CMessageReader() { } - - Dart_CObject* ReadMessage(); - - private: - // Allocates a Dart_CObject object on the C heap. - Dart_CObject* AllocateDartCObject(); - // Allocates a Dart_CObject object with the specified type on the C heap. - Dart_CObject* AllocateDartCObject(Dart_CObject::Type type); - // Allocates a Dart_CObject object for the null object on the C heap. - Dart_CObject* AllocateDartCObjectNull(); - // Allocates a Dart_CObject object for a boolean object on the C heap. - Dart_CObject* AllocateDartCObjectBool(bool value); - // Allocates a Dart_CObject object for for a 32-bit integer on the C heap. - Dart_CObject* AllocateDartCObjectInt32(int32_t value); - // Allocates a Dart_CObject object for a double on the C heap. - Dart_CObject* AllocateDartCObjectDouble(double value); - // Allocates a Dart_CObject object for string data on the C heap. - Dart_CObject* AllocateDartCObjectString(intptr_t length); - // Allocates a C array of Dart_CObject objects on the C heap. - Dart_CObject* AllocateDartCObjectArray(intptr_t length); - - intptr_t LookupInternalClass(intptr_t class_header); - Dart_CObject* ReadInlinedObject(intptr_t object_id); - Dart_CObject* ReadObjectImpl(intptr_t header); - Dart_CObject* ReadIndexedObject(intptr_t object_id); - Dart_CObject* ReadObject(); - - // Add object to backward references. - void AddBackwardReference(intptr_t id, Dart_CObject* obj); - - Dart_CObject_Internal* AsInternal(Dart_CObject* object) { - ASSERT(object->type >= Dart_CObject::kNumberOfTypes); - return reinterpret_cast(object); - } - - ReAlloc alloc_; - GrowableArray backward_references_; - - Dart_CObject type_arguments_marker; - Dart_CObject dynamic_type_marker; -}; - - class BaseWriter { public: // Size of the snapshot. diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc index 9903f10c59c..6d444bdf84d 100644 --- a/runtime/vm/snapshot_test.cc +++ b/runtime/vm/snapshot_test.cc @@ -7,6 +7,7 @@ #include "vm/bigint_operations.h" #include "vm/class_finalizer.h" #include "vm/dart_api_impl.h" +#include "vm/dart_api_message.h" #include "vm/dart_api_state.h" #include "vm/snapshot.h" #include "vm/unit_test.h" @@ -55,7 +56,7 @@ static uint8_t* zone_allocator( static Dart_CObject* DecodeMessage(uint8_t* message, intptr_t length, ReAlloc allocator) { - CMessageReader message_reader(message, length, allocator); + ApiMessageReader message_reader(message, length, allocator); return message_reader.ReadMessage(); } @@ -107,7 +108,6 @@ static void CheckEncodeDecodeMessage(Dart_CObject* root) { MessageWriter writer(&buffer, &malloc_allocator); writer.WriteCMessage(root); - Zone zone(Isolate::Current()); Dart_CObject* new_root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -135,6 +135,7 @@ TEST_CASE(SerializeNull) { EXPECT(Equals(null_object, serialized_object)); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -163,6 +164,7 @@ TEST_CASE(SerializeSmi1) { EXPECT(Equals(smi, serialized_object)); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -192,6 +194,7 @@ TEST_CASE(SerializeSmi2) { EXPECT(Equals(smi, serialized_object)); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -221,6 +224,7 @@ TEST_CASE(SerializeDouble) { EXPECT(Equals(dbl, serialized_object)); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -267,6 +271,7 @@ TEST_CASE(SerializeTrue) { Snapshot::SetupFromBuffer(buffer); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -291,6 +296,7 @@ TEST_CASE(SerializeFalse) { Snapshot::SetupFromBuffer(buffer); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -322,6 +328,7 @@ TEST_CASE(SerializeBigint) { EXPECT_EQ(BigintOperations::ToInt64(bigint), BigintOperations::ToInt64(obj)); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -405,6 +412,7 @@ TEST_CASE(SerializeString) { EXPECT(str.Equals(serialized_str)); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -440,6 +448,7 @@ TEST_CASE(SerializeArray) { EXPECT(array.Equals(serialized_array)); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -475,6 +484,7 @@ TEST_CASE(SerializeEmptyArray) { EXPECT(array.Equals(serialized_array)); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -803,6 +813,7 @@ TEST_CASE(IntArrayMessage) { writer.WriteMessage(len, data); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -892,6 +903,7 @@ UNIT_TEST_CASE(DartGeneratedMessages) { writer.FinalizeBuffer(); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -910,6 +922,7 @@ UNIT_TEST_CASE(DartGeneratedMessages) { writer.FinalizeBuffer(); // Read object back from the snapshot into a C structure. + ApiNativeScope scope; Dart_CObject* root = DecodeMessage(buffer + Snapshot::kHeaderSize, writer.BytesWritten(), &zone_allocator); @@ -962,7 +975,7 @@ UNIT_TEST_CASE(DartGeneratedListMessages) { DARTSCOPE_NOCHECKS(isolate); { // Generate a list of nulls from Dart code. - Zone zone(Isolate::Current()); + ApiNativeScope scope; Dart_CObject* root = GetDeserializedDartMessage(lib, "getList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); @@ -974,7 +987,7 @@ UNIT_TEST_CASE(DartGeneratedListMessages) { } { // Generate a list of ints from Dart code. - Zone zone(Isolate::Current()); + ApiNativeScope scope; Dart_CObject* root = GetDeserializedDartMessage(lib, "getIntList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); @@ -987,7 +1000,7 @@ UNIT_TEST_CASE(DartGeneratedListMessages) { } { // Generate a list of strings from Dart code. - Zone zone(Isolate::Current()); + ApiNativeScope scope; Dart_CObject* root = GetDeserializedDartMessage(lib, "getStringList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); @@ -1001,7 +1014,7 @@ UNIT_TEST_CASE(DartGeneratedListMessages) { } { // Generate a list of objects of different types from Dart code. - Zone zone(Isolate::Current()); + ApiNativeScope scope; Dart_CObject* root = GetDeserializedDartMessage(lib, "getMixedList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); @@ -1072,7 +1085,7 @@ UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) { { // Generate a list of strings from Dart code. - Zone zone(Isolate::Current()); + ApiNativeScope scope; Dart_CObject* root = GetDeserializedDartMessage(lib, "getStringList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); @@ -1086,7 +1099,7 @@ UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) { } { // Generate a list of doubles from Dart code. - Zone zone(Isolate::Current()); + ApiNativeScope scope; Dart_CObject* root = GetDeserializedDartMessage(lib, "getDoubleList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); @@ -1100,7 +1113,7 @@ UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) { } { // Generate a list of objects of different types from Dart code. - Zone zone(Isolate::Current()); + ApiNativeScope scope; Dart_CObject* root = GetDeserializedDartMessage(lib, "getMixedList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); @@ -1120,7 +1133,7 @@ UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) { } { // Generate a list of objects of different types from Dart code. - Zone zone(Isolate::Current()); + ApiNativeScope scope; Dart_CObject* root = GetDeserializedDartMessage(lib, "getSelfRefList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi index fed6e099f91..b0879fd45c7 100644 --- a/runtime/vm/vm_sources.gypi +++ b/runtime/vm/vm_sources.gypi @@ -81,6 +81,8 @@ 'dart_api_impl.h', 'dart_api_state.h', 'dart_api_impl_test.cc', + 'dart_api_message.cc', + 'dart_api_message.h', 'dart_entry.cc', 'dart_entry.h', 'dart_entry_test.cc', diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h index 76cfeef765f..6d05d7e8562 100644 --- a/runtime/vm/zone.h +++ b/runtime/vm/zone.h @@ -91,6 +91,7 @@ class BaseZone { friend class Zone; friend class ApiZone; + template friend class BaseGrowableArray; DISALLOW_COPY_AND_ASSIGN(BaseZone); }; @@ -127,6 +128,8 @@ class Zone : public StackResource { void VisitObjectPointers(ObjectPointerVisitor* visitor); private: + BaseZone* GetBaseZone() { return &zone_; } + BaseZone zone_; // Structure for managing handles allocation. @@ -134,6 +137,10 @@ class Zone : public StackResource { // Used for chaining zones in order to allow unwinding of stacks. Zone* previous_; + + template friend class GrowableArray; + template friend class ZoneGrowableArray; + DISALLOW_IMPLICIT_CONSTRUCTORS(Zone); };