/** Sets a native pointer in an internal field. */
V8EXPORT void SetPointerInInternalField(int index, void* value);
+ class V8EXPORT ExternalResource { // NOLINT
+ public:
+ ExternalResource() {}
+ virtual ~ExternalResource() {}
+
+ protected:
+ virtual void Dispose() { delete this; }
+
+ private:
+ // Disallow copying and assigning.
+ ExternalResource(const ExternalResource&);
+ void operator=(const ExternalResource&);
+
+ friend class v8::internal::Heap;
+ };
+
+ V8EXPORT void SetExternalResource(ExternalResource *);
+ V8EXPORT ExternalResource *GetExternalResource();
+
// Testers for local properties.
V8EXPORT bool HasOwnProperty(Handle<String> key);
V8EXPORT bool HasRealNamedProperty(Handle<String> key);
*/
void SetInternalFieldCount(int value);
+ /**
+ * Sets whether the object can store an "external resource" object.
+ */
+ bool HasExternalResource();
+ void SetHasExternalResource(bool value);
+
private:
ObjectTemplate();
static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
}
+bool ObjectTemplate::HasExternalResource()
+{
+ if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(),
+ "v8::ObjectTemplate::HasExternalResource()")) {
+ return 0;
+ }
+ return !Utils::OpenHandle(this)->has_external_resource()->IsUndefined();
+}
+
+
+void ObjectTemplate::SetHasExternalResource(bool value)
+{
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetHasExternalResource()")) {
+ return;
+ }
+ ENTER_V8(isolate);
+ if (value) {
+ EnsureConstructor(this);
+ }
+ if (value) {
+ Utils::OpenHandle(this)->set_has_external_resource(i::Smi::FromInt(1));
+ } else {
+ Utils::OpenHandle(this)->set_has_external_resource(Utils::OpenHandle(this)->GetHeap()->undefined_value());
+ }
+}
+
+
// --- S c r i p t D a t a ---
}
+void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ENTER_V8(isolate);
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ if (CanBeEncodedAsSmi(resource)) {
+ obj->SetExternalResourceObject(EncodeAsSmi(resource));
+ } else {
+ obj->SetExternalResourceObject(*isolate->factory()->NewForeign(static_cast<i::Address>((void *)resource)));
+ }
+ if (!obj->IsSymbol()) {
+ isolate->heap()->external_string_table()->AddObject(*obj);
+ }
+}
+
+
+v8::Object::ExternalResource *v8::Object::GetExternalResource() {
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ i::Object* value = obj->GetExternalResourceObject();
+ if (value->IsSmi()) {
+ return reinterpret_cast<v8::Object::ExternalResource*>(i::Internals::GetExternalPointerFromSmi(value));
+ } else if (value->IsForeign()) {
+ return reinterpret_cast<v8::Object::ExternalResource*>(i::Foreign::cast(value)->address());
+ } else {
+ return NULL;
+ }
+}
+
+
// --- E n v i r o n m e n t ---
Handle<Code> construct_stub = isolate()->builtins()->JSConstructStubApi();
int internal_field_count = 0;
+ bool has_external_resource = false;
+
if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance_template =
Handle<ObjectTemplateInfo>(
ObjectTemplateInfo::cast(obj->instance_template()));
internal_field_count =
Smi::cast(instance_template->internal_field_count())->value();
+ has_external_resource =
+ !instance_template->has_external_resource()->IsUndefined();
}
int instance_size = kPointerSize * internal_field_count;
+ if (has_external_resource) instance_size += kPointerSize;
+
InstanceType type = INVALID_TYPE;
switch (instance_type) {
case JavaScriptObject:
Handle<Map> map = Handle<Map>(result->initial_map());
+ // Mark as having external data object if needed
+ if (has_external_resource) {
+ map->set_has_external_resource(true);
+ }
+
// Mark as undetectable if needed.
if (obj->undetectable()) {
map->set_is_undetectable();
}
-void Heap::FinalizeExternalString(String* string) {
- ASSERT(string->IsExternalString());
- v8::String::ExternalStringResourceBase** resource_addr =
- reinterpret_cast<v8::String::ExternalStringResourceBase**>(
- reinterpret_cast<byte*>(string) +
- ExternalString::kResourceOffset -
- kHeapObjectTag);
-
- // Dispose of the C++ object if it has not already been disposed.
- if (*resource_addr != NULL) {
- (*resource_addr)->Dispose();
+void Heap::FinalizeExternalString(HeapObject* string) {
+ ASSERT(string->IsExternalString() || string->map()->has_external_resource());
+
+ if (string->IsExternalString()) {
+ v8::String::ExternalStringResourceBase** resource_addr =
+ reinterpret_cast<v8::String::ExternalStringResourceBase**>(
+ reinterpret_cast<byte*>(string) +
+ ExternalString::kResourceOffset -
+ kHeapObjectTag);
+
+ // Dispose of the C++ object if it has not already been disposed.
+ if (*resource_addr != NULL) {
+ (*resource_addr)->Dispose();
+ }
+
+ // Clear the resource pointer in the string.
+ *resource_addr = NULL;
+ } else {
+ JSObject *object = JSObject::cast(string);
+ Object *value = object->GetExternalResourceObject();
+ v8::Object::ExternalResource *resource = 0;
+ if (value->IsSmi()) {
+ resource = reinterpret_cast<v8::Object::ExternalResource*>(Internals::GetExternalPointerFromSmi(value));
+ } else if (value->IsForeign()) {
+ resource = reinterpret_cast<v8::Object::ExternalResource*>(Foreign::cast(value)->address());
+ }
+ if (resource) {
+ resource->Dispose();
+ }
}
-
- // Clear the resource pointer in the string.
- *resource_addr = NULL;
}
}
+void ExternalStringTable::AddObject(HeapObject* object) {
+ ASSERT(object->map()->has_external_resource());
+ if (heap_->InNewSpace(object)) {
+ new_space_strings_.Add(object);
+ } else {
+ old_space_strings_.Add(object);
+ }
+}
+
+
void ExternalStringTable::Iterate(ObjectVisitor* v) {
if (!new_space_strings_.is_empty()) {
Object** start = &new_space_strings_[0];
}
-void ExternalStringTable::AddOldString(String* string) {
- ASSERT(string->IsExternalString());
- ASSERT(!heap_->InNewSpace(string));
- old_space_strings_.Add(string);
+void ExternalStringTable::AddOldObject(HeapObject* object) {
+ ASSERT(object->IsExternalString() || object->map()->has_external_resource());
+ ASSERT(!heap_->InNewSpace(object));
+ old_space_strings_.Add(object);
}
-void ExternalStringTable::ShrinkNewStrings(int position) {
+void ExternalStringTable::ShrinkNewObjects(int position) {
new_space_strings_.Rewind(position);
if (FLAG_verify_heap) {
Verify();
}
-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
- Object** p) {
+HeapObject* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
MapWord first_word = HeapObject::cast(*p)->map_word();
if (!first_word.IsForwardingAddress()) {
// Unreachable external string can be finalized.
- heap->FinalizeExternalString(String::cast(*p));
+ heap->FinalizeExternalString(HeapObject::cast(*p));
return NULL;
}
// String is still reachable.
- return String::cast(first_word.ToForwardingAddress());
+ return HeapObject::cast(first_word.ToForwardingAddress());
}
for (Object** p = start; p < end; ++p) {
ASSERT(InFromSpace(*p));
- String* target = updater_func(this, p);
+ HeapObject* target = updater_func(this, p);
if (target == NULL) continue;
- ASSERT(target->IsExternalString());
+ ASSERT(target->IsExternalString() || target->map()->has_external_resource());
if (InNewSpace(target)) {
// String is still in new space. Update the table entry.
++last;
} else {
// String got promoted. Move it to the old string list.
- external_string_table_.AddOldString(target);
+ external_string_table_.AddOldObject(target);
}
}
ASSERT(last <= end);
- external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
+ external_string_table_.ShrinkNewObjects(static_cast<int>(last - start));
}
void ExternalStringTable::TearDown() {
+ for (int i = 0; i < new_space_strings_.length(); ++i) {
+ if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+ HeapObject *object = HeapObject::cast(new_space_strings_[i]);
+ if (!object->IsExternalString())
+ heap_->FinalizeExternalString(object);
+ }
+ for (int i = 0; i < old_space_strings_.length(); ++i) {
+ if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+ HeapObject *object = HeapObject::cast(old_space_strings_[i]);
+ if (!object->IsExternalString())
+ heap_->FinalizeExternalString(object);
+ }
+
new_space_strings_.Free();
old_space_strings_.Free();
}
class WeakObjectRetainer;
-typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap,
- Object** pointer);
+typedef HeapObject* (*ExternalStringTableUpdaterCallback)(Heap* heap,
+ Object** pointer);
class StoreBufferRebuilder {
public:
// External strings table is a place where all external strings are
// registered. We need to keep track of such strings to properly
// finalize them.
+// The ExternalStringTable can contain both strings and objects with
+// external resources. It was not renamed to make the patch simpler.
class ExternalStringTable {
public:
// Registers an external string.
inline void AddString(String* string);
+ // Registers an external object.
+ inline void AddObject(HeapObject* string);
inline void Iterate(ObjectVisitor* v);
inline void Verify();
- inline void AddOldString(String* string);
+ inline void AddOldObject(HeapObject* string);
// Notifies the table that only a prefix of the new list is valid.
- inline void ShrinkNewStrings(int position);
+ inline void ShrinkNewObjects(int position);
// To speed up scavenge collections new space string are kept
// separate from old space strings.
// Finalizes an external string by deleting the associated external
// data and clearing the resource pointer.
- inline void FinalizeExternalString(String* string);
+ inline void FinalizeExternalString(HeapObject* string);
// Allocates an uninitialized object. The memory is non-executable if the
// hardware and OS allow.
// Performs a minor collection in new generation.
void Scavenge();
- static String* UpdateNewSpaceReferenceInExternalStringTableEntry(
+ static HeapObject* UpdateNewSpaceReferenceInExternalStringTableEntry(
Heap* heap,
Object** pointer);
// Since no objects have yet been moved we can safely access the map of
// the object.
- if (o->IsExternalString()) {
- heap_->FinalizeExternalString(String::cast(*p));
+ if (o->IsExternalString() ||
+ (o->IsHeapObject() && HeapObject::cast(o)->map()->has_external_resource())) {
+ heap_->FinalizeExternalString(HeapObject::cast(*p));
}
// Set the entry to null_value (as deleted).
*p = heap_->null_value();
}
-static String* UpdateReferenceInExternalStringTableEntry(Heap* heap,
- Object** p) {
+static HeapObject* UpdateReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
MapWord map_word = HeapObject::cast(*p)->map_word();
if (map_word.IsForwardingAddress()) {
- return String::cast(map_word.ToForwardingAddress());
+ return HeapObject::cast(map_word.ToForwardingAddress());
}
- return String::cast(*p);
+ return HeapObject::cast(*p);
}
// Make sure to adjust for the number of in-object properties. These
// properties do contribute to the size, but are not internal fields.
return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) -
- map()->inobject_properties();
+ map()->inobject_properties() - (map()->has_external_resource()?1:0);
}
}
+void JSObject::SetExternalResourceObject(Object *value) {
+ ASSERT(map()->has_external_resource());
+ int offset = GetHeaderSize() + kPointerSize * GetInternalFieldCount();
+ WRITE_FIELD(this, offset, value);
+ WRITE_BARRIER(GetHeap(), this, offset, value);
+}
+
+
+Object *JSObject::GetExternalResourceObject() {
+ if (map()->has_external_resource()) {
+ return READ_FIELD(this, GetHeaderSize() + kPointerSize * GetInternalFieldCount());
+ } else {
+ return GetHeap()->undefined_value();
+ }
+}
+
+
// Access fast-case object properties at index. The use of these routines
// is needed to correctly distinguish between properties stored in-object and
// properties stored in the properties array.
return ((1 << kIsShared) & bit_field3()) != 0;
}
+void Map::set_has_external_resource(bool value) {
+ if (value) {
+ set_bit_field(bit_field() | (1 << kHasExternalResource));
+ } else {
+ set_bit_field(bit_field() & ~(1 << kHasExternalResource));
+ }
+}
+
+bool Map::has_external_resource()
+{
+ return ((1 << kHasExternalResource) & bit_field()) != 0;
+}
+
+
void Map::set_named_interceptor_is_fallback(bool value)
{
if (value) {
ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset)
ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
kInternalFieldCountOffset)
+ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
+ kHasExternalResourceOffset)
ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
inline Object* GetInternalField(int index);
inline void SetInternalField(int index, Object* value);
+ inline void SetExternalResourceObject(Object *);
+ inline Object *GetExternalResourceObject();
+
// The following lookup functions skip interceptors.
void LocalLookupRealNamedProperty(String* name, LookupResult* result);
void LookupRealNamedProperty(String* name, LookupResult* result);
// Tells whether the instance has a call-as-function handler.
inline void set_has_instance_call_handler() {
- set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));
+ set_bit_field3(bit_field3() | (1 << kHasInstanceCallHandler));
}
inline bool has_instance_call_handler() {
- return ((1 << kHasInstanceCallHandler) & bit_field()) != 0;
+ return ((1 << kHasInstanceCallHandler) & bit_field3()) != 0;
}
inline void set_is_extensible(bool value);
inline void set_named_interceptor_is_fallback(bool value);
inline bool named_interceptor_is_fallback();
+ // Tells whether the instance has the space for an external resource
+ // object
+ inline void set_has_external_resource(bool value);
+ inline bool has_external_resource();
+
// [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object)
static const int kHasNamedInterceptor = 3;
static const int kHasIndexedInterceptor = 4;
static const int kIsUndetectable = 5;
- static const int kHasInstanceCallHandler = 6;
+ static const int kHasExternalResource = 6;
static const int kIsAccessCheckNeeded = 7;
// Bit positions for bit field 2
// Bit positions for bit field 3
static const int kIsShared = 0;
static const int kNamedInterceptorIsFallback = 1;
+ static const int kHasInstanceCallHandler = 2;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
public:
DECL_ACCESSORS(constructor, Object)
DECL_ACCESSORS(internal_field_count, Object)
+ DECL_ACCESSORS(has_external_resource, Object)
static inline ObjectTemplateInfo* cast(Object* obj);
static const int kConstructorOffset = TemplateInfo::kHeaderSize;
static const int kInternalFieldCountOffset =
kConstructorOffset + kPointerSize;
- static const int kSize = kInternalFieldCountOffset + kPointerSize;
+ static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
+ static const int kSize = kHasExternalResourceOffset + kPointerSize;
};