Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(574)

Unified Diff: src/objects.cc

Issue 7535004: Merge bleeding edge up to 8774 into the GC branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
===================================================================
--- src/objects.cc (revision 8778)
+++ src/objects.cc (working copy)
@@ -60,11 +60,6 @@
const int kGetterIndex = 0;
const int kSetterIndex = 1;
-uint64_t FixedDoubleArray::kHoleNanInt64 = -1;
-uint64_t FixedDoubleArray::kCanonicalNonHoleNanLower32 = 0x7FF00000;
-uint64_t FixedDoubleArray::kCanonicalNonHoleNanInt64 =
- kCanonicalNonHoleNanLower32 << 32;
-
MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
Object* value) {
Object* result;
@@ -196,7 +191,7 @@
AccessorInfo* data = AccessorInfo::cast(structure);
Object* fun_obj = data->getter();
v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
- HandleScope scope;
+ HandleScope scope(isolate);
JSObject* self = JSObject::cast(receiver);
JSObject* holder_handle = JSObject::cast(holder);
Handle<String> key(name);
@@ -236,7 +231,7 @@
String* name_raw,
Object* handler_raw) {
Isolate* isolate = name_raw->GetIsolate();
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<Object> receiver(receiver_raw);
Handle<Object> name(name_raw);
Handle<Object> handler(handler_raw);
@@ -1896,13 +1891,9 @@
pt = pt->GetPrototype()) {
JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
if (result->IsProperty()) {
- if (result->IsReadOnly()) {
- result->NotFound();
- return;
- }
- if (result->type() == CALLBACKS) {
- return;
- }
+ if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
+ // Found non-callback or read-only callback, stop looking.
+ break;
}
}
result->NotFound();
@@ -2196,9 +2187,9 @@
}
}
- HandleScope scope;
+ Heap* heap = GetHeap();
+ HandleScope scope(heap->isolate());
Handle<Object> value_handle(value);
- Heap* heap = GetHeap();
heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle;
}
@@ -2219,13 +2210,38 @@
}
+bool JSProxy::HasPropertyWithHandler(String* name_raw) {
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+ Handle<Object> receiver(this);
+ Handle<Object> name(name_raw);
+ Handle<Object> handler(this->handler());
+
+ // Extract trap function.
+ Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (trap->IsUndefined()) {
+ trap = isolate->derived_has_trap();
+ }
+
+ // Call trap function.
+ Object** args[] = { name.location() };
+ bool has_exception;
+ Handle<Object> result =
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ if (has_exception) return Failure::Exception();
+
+ return result->ToBoolean()->IsTrue();
+}
+
+
MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
String* name_raw,
Object* value_raw,
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
Isolate* isolate = GetIsolate();
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<Object> receiver(this);
Handle<Object> name(name_raw);
Handle<Object> value(value_raw);
@@ -2243,11 +2259,48 @@
receiver.location(), name.location(), value.location()
};
bool has_exception;
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ if (has_exception) return Failure::Exception();
+
+ return *value;
+}
+
+
+MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
+ String* name_raw, DeleteMode mode) {
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+ Handle<Object> receiver(this);
+ Handle<Object> name(name_raw);
+ Handle<Object> handler(this->handler());
+
+ // Extract trap function.
+ Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (trap->IsUndefined()) {
+ Handle<Object> args[] = { handler, trap_name };
+ Handle<Object> error = isolate->factory()->NewTypeError(
+ "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
+ isolate->Throw(*error);
+ return Failure::Exception();
+ }
+
+ // Call trap function.
+ Object** args[] = { name.location() };
+ bool has_exception;
Handle<Object> result =
Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
if (has_exception) return Failure::Exception();
- return *value;
+ Object* bool_result = result->ToBoolean();
+ if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
+ Handle<Object> args[] = { handler, trap_name };
+ Handle<Object> error = isolate->factory()->NewTypeError(
+ "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
+ isolate->Throw(*error);
+ return Failure::Exception();
+ }
+ return bool_result;
}
@@ -2256,7 +2309,7 @@
String* name_raw,
bool* has_exception) {
Isolate* isolate = GetIsolate();
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<JSReceiver> receiver(receiver_raw);
Handle<Object> name(name_raw);
Handle<Object> handler(this->handler());
@@ -2286,11 +2339,23 @@
}
+void JSProxy::Fix() {
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+ Handle<JSProxy> self(this);
+
+ isolate->factory()->BecomeJSObject(self);
+ ASSERT(self->IsJSObject());
+ // TODO(rossberg): recognize function proxies.
+}
+
+
+
MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
- String* name,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode) {
+ String* name,
+ Object* value,
+ PropertyAttributes attributes,
+ StrictModeFlag strict_mode) {
Heap* heap = GetHeap();
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
@@ -2345,7 +2410,7 @@
}
if (result->IsReadOnly() && result->IsProperty()) {
if (strict_mode == kStrictMode) {
- HandleScope scope;
+ HandleScope scope(heap->isolate());
Handle<String> key(name);
Handle<Object> holder(this);
Handle<Object> args[2] = { key, holder };
@@ -2420,6 +2485,9 @@
// callback setter removed. The two lines looking up the LookupResult
// result are also added. If one of the functions is changed, the other
// should be.
+// Note that this method cannot be used to set the prototype of a function
+// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
+// doesn't handle function prototypes correctly.
MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
String* name,
Object* value,
@@ -2833,29 +2901,34 @@
ASSERT(!HasExternalArrayElements());
// Find the backing store.
- FixedArray* array = FixedArray::cast(elements());
+ FixedArrayBase* array = FixedArrayBase::cast(elements());
Map* old_map = array->map();
bool is_arguments =
(old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
if (is_arguments) {
- array = FixedArray::cast(array->get(1));
+ array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
}
if (array->IsDictionary()) return array;
- ASSERT(HasFastElements() || HasFastArgumentsElements());
+ ASSERT(HasFastElements() ||
+ HasFastDoubleElements() ||
+ HasFastArgumentsElements());
// Compute the effective length and allocate a new backing store.
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
: array->length();
+ int old_capacity = 0;
+ int used_elements = 0;
+ GetElementsCapacityAndUsage(&old_capacity, &used_elements);
NumberDictionary* dictionary = NULL;
{ Object* object;
- MaybeObject* maybe = NumberDictionary::Allocate(length);
+ MaybeObject* maybe = NumberDictionary::Allocate(used_elements);
if (!maybe->ToObject(&object)) return maybe;
dictionary = NumberDictionary::cast(object);
}
// Copy the elements to the new backing store.
- bool has_double_elements = old_map->has_fast_double_elements();
+ bool has_double_elements = array->IsFixedDoubleArray();
for (int i = 0; i < length; i++) {
Object* value = NULL;
if (has_double_elements) {
@@ -2873,7 +2946,7 @@
}
} else {
ASSERT(old_map->has_fast_elements());
- value = array->get(i);
+ value = FixedArray::cast(array)->get(i);
}
PropertyDetails details = PropertyDetails(NONE, NORMAL);
if (!value->IsTheHole()) {
@@ -2913,6 +2986,91 @@
}
+MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) {
+ Isolate* isolate = GetIsolate();
+ Heap* heap = isolate->heap();
+ Object* holder = BypassGlobalProxy();
+ if (holder->IsUndefined()) return heap->undefined_value();
+ JSObject* obj = JSObject::cast(holder);
+ if (obj->HasFastProperties()) {
+ // If the object has fast properties, check whether the first slot
+ // in the descriptor array matches the hidden symbol. Since the
+ // hidden symbols hash code is zero (and no other string has hash
+ // code zero) it will always occupy the first entry if present.
+ DescriptorArray* descriptors = obj->map()->instance_descriptors();
+ if ((descriptors->number_of_descriptors() > 0) &&
+ (descriptors->GetKey(0) == heap->hidden_symbol()) &&
+ descriptors->IsProperty(0)) {
+ ASSERT(descriptors->GetType(0) == FIELD);
+ return obj->FastPropertyAt(descriptors->GetFieldIndex(0));
+ }
+ }
+
+ // Only attempt to find the hidden properties in the local object and not
+ // in the prototype chain.
+ if (!obj->HasHiddenPropertiesObject()) {
+ // Hidden properties object not found. Allocate a new hidden properties
+ // object if requested. Otherwise return the undefined value.
+ if (flag == ALLOW_CREATION) {
+ Object* hidden_obj;
+ { MaybeObject* maybe_obj = heap->AllocateJSObject(
+ isolate->context()->global_context()->object_function());
+ if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj;
+ }
+ return obj->SetHiddenPropertiesObject(hidden_obj);
+ } else {
+ return heap->undefined_value();
+ }
+ }
+ return obj->GetHiddenPropertiesObject();
+}
+
+
+MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) {
+ Isolate* isolate = GetIsolate();
+ Object* hidden_props_obj;
+ { MaybeObject* maybe_obj = GetHiddenProperties(flag);
+ if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj;
+ }
+ if (!hidden_props_obj->IsJSObject()) {
+ // We failed to create hidden properties. That's a detached
+ // global proxy.
+ ASSERT(hidden_props_obj->IsUndefined());
+ return Smi::FromInt(0);
+ }
+ JSObject* hidden_props = JSObject::cast(hidden_props_obj);
+ String* hash_symbol = isolate->heap()->identity_hash_symbol();
+ {
+ // Note that HasLocalProperty() can cause a GC in the general case in the
+ // presence of interceptors.
+ AssertNoAllocation no_alloc;
+ if (hidden_props->HasLocalProperty(hash_symbol)) {
+ MaybeObject* hash = hidden_props->GetProperty(hash_symbol);
+ return Smi::cast(hash->ToObjectChecked());
+ }
+ }
+
+ int hash_value;
+ int attempts = 0;
+ do {
+ // Generate a random 32-bit hash value but limit range to fit
+ // within a smi.
+ hash_value = V8::Random(isolate) & Smi::kMaxValue;
+ attempts++;
+ } while (hash_value == 0 && attempts < 30);
+ hash_value = hash_value != 0 ? hash_value : 1; // never return 0
+
+ Smi* hash = Smi::FromInt(hash_value);
+ { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes(
+ hash_symbol,
+ hash,
+ static_cast<PropertyAttributes>(None));
+ if (result->IsFailure()) return result;
+ }
+ return hash;
+}
+
+
MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
DeleteMode mode) {
// Check local property, ignore interceptor.
@@ -3158,7 +3316,7 @@
case FAST_DOUBLE_ELEMENTS: {
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
- : FixedArray::cast(elements())->length();
+ : FixedDoubleArray::cast(elements())->length();
if (index < static_cast<uint32_t>(length)) {
FixedDoubleArray::cast(elements())->set_the_hole(index);
}
@@ -3202,6 +3360,15 @@
}
+MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
+ if (IsJSProxy()) {
+ return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
+ } else {
+ return JSObject::cast(this)->DeleteProperty(name, mode);
+ }
+}
+
+
MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Isolate* isolate = GetIsolate();
// ECMA-262, 3rd, 8.6.2.5
@@ -3599,6 +3766,7 @@
if (is_element) {
switch (GetElementsKind()) {
case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
break;
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
@@ -3609,7 +3777,6 @@
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
// Ignore getters and setters on pixel and external array
// elements.
return heap->undefined_value();
@@ -3848,6 +4015,7 @@
// Accessors overwrite previous callbacks (cf. with getters/setters).
switch (GetElementsKind()) {
case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
break;
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
@@ -3858,7 +4026,6 @@
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
// Ignore getters and setters on pixel and external array
// elements.
return isolate->heap()->undefined_value();
@@ -4631,6 +4798,9 @@
switch (array->GetElementsKind()) {
case JSObject::FAST_ELEMENTS:
return UnionOfKeys(FixedArray::cast(array->elements()));
+ case JSObject::FAST_DOUBLE_ELEMENTS:
+ return UnionOfDoubleKeys(FixedDoubleArray::cast(array->elements()));
+ break;
case JSObject::DICTIONARY_ELEMENTS: {
NumberDictionary* dict = array->element_dictionary();
int size = dict->NumberOfElements();
@@ -4665,7 +4835,6 @@
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
break;
}
UNREACHABLE();
@@ -4727,6 +4896,69 @@
}
+MaybeObject* FixedArray::UnionOfDoubleKeys(FixedDoubleArray* other) {
+ int len0 = length();
+#ifdef DEBUG
+ if (FLAG_enable_slow_asserts) {
+ for (int i = 0; i < len0; i++) {
+ ASSERT(get(i)->IsString() || get(i)->IsNumber());
+ }
+ }
+#endif
+ int len1 = other->length();
+ // Optimize if 'other' is empty.
+ // We cannot optimize if 'this' is empty, as other may have holes
+ // or non keys.
+ if (len1 == 0) return this;
+
+ // Compute how many elements are not in this.
+ int extra = 0;
+ Heap* heap = GetHeap();
+ Object* obj;
+ for (int y = 0; y < len1; y++) {
+ if (!other->is_the_hole(y)) {
+ MaybeObject* maybe_obj = heap->NumberFromDouble(other->get(y));
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ if (!HasKey(this, obj)) extra++;
+ }
+ }
+
+ if (extra == 0) return this;
+
+ // Allocate the result
+ { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ // Fill in the content
+ FixedArray* result = FixedArray::cast(obj);
+ {
+ // Limit the scope of the AssertNoAllocation
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
+ for (int i = 0; i < len0; i++) {
+ Object* e = get(i);
+ ASSERT(e->IsString() || e->IsNumber());
+ result->set(i, e, mode);
+ }
+ }
+
+ // Fill in the extra keys.
+ int index = 0;
+ for (int y = 0; y < len1; y++) {
+ if (!other->is_the_hole(y)) {
+ MaybeObject* maybe_obj = heap->NumberFromDouble(other->get(y));
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ if (!HasKey(this, obj)) {
+ result->set(len0 + index, obj);
+ index++;
+ }
+ }
+ }
+ ASSERT(extra == index);
+ return result;
+}
+
+
MaybeObject* FixedArray::CopySize(int new_length) {
Heap* heap = GetHeap();
if (new_length == 0) return heap->empty_fixed_array();
@@ -7152,6 +7384,7 @@
case UNARY_OP_IC: return "UNARY_OP_IC";
case BINARY_OP_IC: return "BINARY_OP_IC";
case COMPARE_IC: return "COMPARE_IC";
+ case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
}
UNREACHABLE();
return NULL;
@@ -7342,22 +7575,28 @@
new_map = Map::cast(object);
}
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
switch (GetElementsKind()) {
- case FAST_ELEMENTS:
+ case FAST_ELEMENTS: {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
set_map(new_map);
set_elements(new_elements);
break;
- case DICTIONARY_ELEMENTS:
+ }
+ case DICTIONARY_ELEMENTS: {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
CopySlowElementsToFast(NumberDictionary::cast(elements()),
new_elements,
mode);
set_map(new_map);
set_elements(new_elements);
break;
+ }
case NON_STRICT_ARGUMENTS_ELEMENTS: {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
// The object's map and the parameter map are unchanged, the unaliased
// arguments are copied to the new backing store.
FixedArray* parameter_map = FixedArray::cast(elements());
@@ -7393,6 +7632,8 @@
new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
}
}
+ set_map(new_map);
+ set_elements(new_elements);
break;
}
case EXTERNAL_BYTE_ELEMENTS:
@@ -7455,7 +7696,9 @@
break;
}
+ ASSERT(new_map->has_fast_double_elements());
set_map(new_map);
+ ASSERT(elems->IsFixedDoubleArray());
set_elements(elems);
if (IsJSArray()) {
@@ -7474,9 +7717,10 @@
switch (GetElementsKind()) {
case FAST_ELEMENTS: {
+ case FAST_DOUBLE_ELEMENTS:
// Make sure we never try to shrink dense arrays into sparse arrays.
- ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
- new_length);
+ ASSERT(static_cast<uint32_t>(
+ FixedArrayBase::cast(elements())->length()) <= new_length);
MaybeObject* result = NormalizeElements();
if (result->IsFailure()) return result;
@@ -7505,7 +7749,6 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
UNREACHABLE();
break;
}
@@ -7545,7 +7788,7 @@
static Failure* ArrayLengthRangeError(Heap* heap) {
- HandleScope scope;
+ HandleScope scope(heap->isolate());
return heap->isolate()->Throw(
*FACTORY->NewRangeError("invalid_array_length",
HandleVector<Object>(NULL, 0)));
@@ -7561,32 +7804,57 @@
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value();
if (value < 0) return ArrayLengthRangeError(GetHeap());
- switch (GetElementsKind()) {
- case FAST_ELEMENTS: {
- int old_capacity = FixedArray::cast(elements())->length();
+ JSObject::ElementsKind elements_kind = GetElementsKind();
+ switch (elements_kind) {
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS: {
+ int old_capacity = FixedArrayBase::cast(elements())->length();
if (value <= old_capacity) {
if (IsJSArray()) {
Object* obj;
- { MaybeObject* maybe_obj = EnsureWritableFastElements();
+ if (elements_kind == FAST_ELEMENTS) {
+ MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- FixedArray* fast_elements = FixedArray::cast(elements());
if (2 * value <= old_capacity) {
// If more than half the elements won't be used, trim the array.
if (value == 0) {
initialize_elements();
} else {
- fast_elements->set_length(value);
- Address filler_start = fast_elements->address() +
- FixedArray::OffsetOfElementAt(value);
- int filler_size = (old_capacity - value) * kPointerSize;
+ Address filler_start;
+ int filler_size;
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ FixedArray* fast_elements = FixedArray::cast(elements());
+ fast_elements->set_length(value);
+ filler_start = fast_elements->address() +
+ FixedArray::OffsetOfElementAt(value);
+ filler_size = (old_capacity - value) * kPointerSize;
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ FixedDoubleArray* fast_double_elements =
+ FixedDoubleArray::cast(elements());
+ fast_double_elements->set_length(value);
+ filler_start = fast_double_elements->address() +
+ FixedDoubleArray::OffsetOfElementAt(value);
+ filler_size = (old_capacity - value) * kDoubleSize;
+ }
GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
}
} else {
// Otherwise, fill the unused tail with holes.
int old_length = FastD2I(JSArray::cast(this)->length()->Number());
- for (int i = value; i < old_length; i++) {
- fast_elements->set_the_hole(i);
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ FixedArray* fast_elements = FixedArray::cast(elements());
+ for (int i = value; i < old_length; i++) {
+ fast_elements->set_the_hole(i);
+ }
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ FixedDoubleArray* fast_double_elements =
+ FixedDoubleArray::cast(elements());
+ for (int i = value; i < old_length; i++) {
+ fast_double_elements->set_the_hole(i);
+ }
}
}
JSArray::cast(this)->set_length(Smi::cast(smi_length));
@@ -7595,10 +7863,15 @@
}
int min = NewElementsCapacity(old_capacity);
int new_capacity = value > min ? value : min;
- if (new_capacity <= kMaxFastElementsLength ||
- !ShouldConvertToSlowElements(new_capacity)) {
- MaybeObject* result =
- SetFastElementsCapacityAndLength(new_capacity, value);
+ if (!ShouldConvertToSlowElements(new_capacity)) {
+ MaybeObject* result;
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ result = SetFastElementsCapacityAndLength(new_capacity, value);
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ result = SetFastDoubleElementsCapacityAndLength(new_capacity,
+ value);
+ }
if (result->IsFailure()) return result;
return this;
}
@@ -7634,7 +7907,6 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
UNREACHABLE();
break;
}
@@ -7743,7 +8015,7 @@
// or [[Extensible]] must not violate the invariants defined in the preceding
// paragraph.
if (!this->map()->is_extensible()) {
- HandleScope scope;
+ HandleScope scope(heap->isolate());
Handle<Object> handle(this, heap->isolate());
return heap->isolate()->Throw(
*FACTORY->NewTypeError("non_extensible_proto",
@@ -7757,7 +8029,7 @@
for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
if (JSObject::cast(pt) == this) {
// Cycle detected.
- HandleScope scope;
+ HandleScope scope(heap->isolate());
return heap->isolate()->Throw(
*FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
}
@@ -7817,6 +8089,17 @@
}
break;
}
+ case FAST_DOUBLE_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>
+ (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+ if ((index < length) &&
+ !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
+ return true;
+ }
+ break;
+ }
case EXTERNAL_PIXEL_ELEMENTS: {
ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) {
@@ -7831,8 +8114,7 @@
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS: {
+ case EXTERNAL_DOUBLE_ELEMENTS: {
ExternalArray* array = ExternalArray::cast(elements());
if (index < static_cast<uint32_t>(array->length())) {
return true;
@@ -7943,6 +8225,17 @@
}
break;
}
+ case FAST_DOUBLE_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>
+ (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+ if ((index < length) &&
+ !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
+ return FAST_ELEMENT;
+ }
+ break;
+ }
case EXTERNAL_PIXEL_ELEMENTS: {
ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
@@ -7960,9 +8253,6 @@
if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
break;
}
- case FAST_DOUBLE_ELEMENTS:
- UNREACHABLE();
- break;
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index) !=
NumberDictionary::kNotFound) {
@@ -8047,6 +8337,15 @@
!FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
break;
}
+ case FAST_DOUBLE_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>
+ (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+ if ((index < length) &&
+ !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
+ break;
+ }
case EXTERNAL_PIXEL_ELEMENTS: {
ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) {
@@ -8068,9 +8367,6 @@
}
break;
}
- case FAST_DOUBLE_ELEMENTS:
- UNREACHABLE();
- break;
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) {
@@ -8323,8 +8619,7 @@
if ((index - length) < kMaxGap) {
// Try allocating extra space.
int new_capacity = NewElementsCapacity(index + 1);
- if (new_capacity <= kMaxFastElementsLength ||
- !ShouldConvertToSlowElements(new_capacity)) {
+ if (!ShouldConvertToSlowElements(new_capacity)) {
ASSERT(static_cast<uint32_t>(new_capacity) > index);
Object* new_elements;
MaybeObject* maybe =
@@ -8432,8 +8727,9 @@
} else {
new_length = dictionary->max_number_key() + 1;
}
- MaybeObject* result =
- SetFastElementsCapacityAndLength(new_length, new_length);
+ MaybeObject* result = CanConvertToFastDoubleElements()
+ ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
+ : SetFastElementsCapacityAndLength(new_length, new_length);
if (result->IsFailure()) return result;
#ifdef DEBUG
if (FLAG_trace_normalization) {
@@ -8505,8 +8801,7 @@
if ((index - elms_length) < kMaxGap) {
// Try allocating extra space.
int new_capacity = NewElementsCapacity(index+1);
- if (new_capacity <= kMaxFastElementsLength ||
- !ShouldConvertToSlowElements(new_capacity)) {
+ if (!ShouldConvertToSlowElements(new_capacity)) {
ASSERT(static_cast<uint32_t>(new_capacity) > index);
Object* obj;
{ MaybeObject* maybe_obj =
@@ -8520,6 +8815,9 @@
}
// Otherwise default to slow case.
+ ASSERT(HasFastDoubleElements());
+ ASSERT(map()->has_fast_double_elements());
+ ASSERT(elements()->IsFixedDoubleArray());
Object* obj;
{ MaybeObject* maybe_obj = NormalizeElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@@ -8537,7 +8835,7 @@
if (IsAccessCheckNeeded()) {
Heap* heap = GetHeap();
if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
- HandleScope scope;
+ HandleScope scope(heap->isolate());
Handle<Object> value_handle(value);
heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle;
@@ -8971,40 +9269,52 @@
bool JSObject::HasDenseElements() {
int capacity = 0;
- int number_of_elements = 0;
+ int used = 0;
+ GetElementsCapacityAndUsage(&capacity, &used);
+ return (capacity == 0) || (used > (capacity / 2));
+}
- FixedArray* backing_store = FixedArray::cast(elements());
+
+void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
+ *capacity = 0;
+ *used = 0;
+
+ FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
+ FixedArray* backing_store = NULL;
switch (GetElementsKind()) {
case NON_STRICT_ARGUMENTS_ELEMENTS:
- backing_store = FixedArray::cast(backing_store->get(1));
+ backing_store_base =
+ FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
+ backing_store = FixedArray::cast(backing_store_base);
if (backing_store->IsDictionary()) {
NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
- capacity = dictionary->Capacity();
- number_of_elements = dictionary->NumberOfElements();
+ *capacity = dictionary->Capacity();
+ *used = dictionary->NumberOfElements();
break;
}
// Fall through.
case FAST_ELEMENTS:
- capacity = backing_store->length();
- for (int i = 0; i < capacity; ++i) {
- if (!backing_store->get(i)->IsTheHole()) ++number_of_elements;
+ backing_store = FixedArray::cast(backing_store_base);
+ *capacity = backing_store->length();
+ for (int i = 0; i < *capacity; ++i) {
+ if (!backing_store->get(i)->IsTheHole()) ++(*used);
}
break;
case DICTIONARY_ELEMENTS: {
- NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
- capacity = dictionary->Capacity();
- number_of_elements = dictionary->NumberOfElements();
+ NumberDictionary* dictionary =
+ NumberDictionary::cast(FixedArray::cast(elements()));
+ *capacity = dictionary->Capacity();
+ *used = dictionary->NumberOfElements();
break;
}
case FAST_DOUBLE_ELEMENTS: {
FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
- capacity = elms->length();
- for (int i = 0; i < capacity; i++) {
- if (!elms->is_the_hole(i)) number_of_elements++;
+ *capacity = elms->length();
+ for (int i = 0; i < *capacity; i++) {
+ if (!elms->is_the_hole(i)) ++(*used);
}
break;
}
- case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
@@ -9012,30 +9322,34 @@
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS: {
- return true;
- }
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ // External arrays are considered 100% used.
+ ExternalArray* external_array = ExternalArray::cast(elements());
+ *capacity = external_array->length();
+ *used = external_array->length();
+ break;
}
- return (capacity == 0) || (number_of_elements > (capacity / 2));
}
bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
- // Keep the array in fast case if the current backing storage is
- // almost filled and if the new capacity is no more than twice the
- // old capacity.
- int elements_length = 0;
- if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
- FixedArray* backing_store = FixedArray::cast(elements());
- elements_length = FixedArray::cast(backing_store->get(1))->length();
- } else if (HasFastElements()) {
- elements_length = FixedArray::cast(elements())->length();
- } else if (HasFastDoubleElements()) {
- elements_length = FixedDoubleArray::cast(elements())->length();
- } else {
- UNREACHABLE();
+ STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
+ kMaxUncheckedFastElementsLength);
+ if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
+ (new_capacity <= kMaxUncheckedFastElementsLength &&
+ GetHeap()->InNewSpace(this))) {
+ return false;
}
- return !HasDenseElements() || ((new_capacity / 2) > elements_length);
+ // If the fast-case backing storage takes up roughly three times as
+ // much space (in machine words) as a dictionary backing storage
+ // would, the object should have slow elements.
+ int old_capacity = 0;
+ int used_elements = 0;
+ GetElementsCapacityAndUsage(&old_capacity, &used_elements);
+ int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) *
+ NumberDictionary::kEntrySize;
+ return 3 * dictionary_size <= new_capacity;
}
@@ -9058,20 +9372,21 @@
// dictionary, we cannot go back to fast case.
if (dictionary->requires_slow_elements()) return false;
// If the dictionary backing storage takes up roughly half as much
- // space as a fast-case backing storage would the array should have
- // fast elements.
- uint32_t length = 0;
+ // space (in machine words) as a fast-case backing storage would,
+ // the object should have fast elements.
+ uint32_t array_size = 0;
if (IsJSArray()) {
- CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
+ CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
} else {
- length = dictionary->max_number_key();
+ array_size = dictionary->max_number_key();
}
- return static_cast<uint32_t>(dictionary->Capacity()) >=
- (length / (2 * NumberDictionary::kEntrySize));
+ uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
+ NumberDictionary::kEntrySize;
+ return 2 * dictionary_size >= array_size;
}
-bool JSObject::ShouldConvertToFastDoubleElements() {
+bool JSObject::CanConvertToFastDoubleElements() {
if (FLAG_unbox_double_arrays) {
ASSERT(HasDictionaryElements());
NumberDictionary* dictionary = NumberDictionary::cast(elements());
@@ -9261,6 +9576,15 @@
return (index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole();
}
+ case FAST_DOUBLE_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>(
+ Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+ return (index < length) &&
+ !FixedDoubleArray::cast(elements())->is_the_hole(index);
+ break;
+ }
case EXTERNAL_PIXEL_ELEMENTS: {
ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
return index < static_cast<uint32_t>(pixels->length());
@@ -9276,9 +9600,6 @@
ExternalArray* array = ExternalArray::cast(elements());
return index < static_cast<uint32_t>(array->length());
}
- case FAST_DOUBLE_ELEMENTS:
- UNREACHABLE();
- break;
case DICTIONARY_ELEMENTS: {
return element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound;
@@ -9499,6 +9820,21 @@
ASSERT(!storage || storage->length() >= counter);
break;
}
+ case FAST_DOUBLE_ELEMENTS: {
+ int length = IsJSArray() ?
+ Smi::cast(JSArray::cast(this)->length())->value() :
+ FixedDoubleArray::cast(elements())->length();
+ for (int i = 0; i < length; i++) {
+ if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
+ if (storage != NULL) {
+ storage->set(counter, Smi::FromInt(i));
+ }
+ counter++;
+ }
+ }
+ ASSERT(!storage || storage->length() >= counter);
+ break;
+ }
case EXTERNAL_PIXEL_ELEMENTS: {
int length = ExternalPixelArray::cast(elements())->length();
while (counter < length) {
@@ -9528,9 +9864,6 @@
ASSERT(!storage || storage->length() >= counter);
break;
}
- case FAST_DOUBLE_ELEMENTS:
- UNREACHABLE();
- break;
case DICTIONARY_ELEMENTS: {
if (storage != NULL) {
element_dictionary()->CopyKeysTo(storage,
@@ -9984,11 +10317,8 @@
template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
PretenureFlag pretenure) {
- const int kMinCapacity = 32;
- int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
- if (capacity < kMinCapacity) {
- capacity = kMinCapacity; // Guarantee min capacity.
- } else if (capacity > HashTable::kMaxCapacity) {
+ int capacity = ComputeCapacity(at_least_space_for);
+ if (capacity > HashTable::kMaxCapacity) {
return Failure::OutOfMemoryException();
}
@@ -10156,6 +10486,8 @@
template class HashTable<MapCacheShape, HashTableKey*>;
+template class HashTable<ObjectHashTableShape, JSObject*>;
+
template class Dictionary<StringDictionaryShape, String*>;
template class Dictionary<NumberDictionaryShape, uint32_t>;
@@ -11078,11 +11410,11 @@
template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
- JSObject::DeleteMode mode) {
+ JSReceiver::DeleteMode mode) {
Heap* heap = Dictionary<Shape, Key>::GetHeap();
PropertyDetails details = DetailsAt(entry);
// Ignore attributes if forcing a deletion.
- if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
+ if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
return heap->false_value();
}
SetEntry(entry, heap->null_value(), heap->null_value());
@@ -11467,6 +11799,64 @@
}
+Object* ObjectHashTable::Lookup(JSObject* key) {
+ // If the object does not have an identity hash, it was never used as a key.
+ MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION);
+ if (maybe_hash->IsFailure()) return GetHeap()->undefined_value();
+ int entry = FindEntry(key);
+ if (entry == kNotFound) return GetHeap()->undefined_value();
+ return get(EntryToIndex(entry) + 1);
+}
+
+
+MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) {
+ // Make sure the key object has an identity hash code.
+ int hash;
+ { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION);
+ if (maybe_hash->IsFailure()) return maybe_hash;
+ hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
+ }
+ int entry = FindEntry(key);
+
+ // Check whether to perform removal operation.
+ if (value->IsUndefined()) {
+ if (entry == kNotFound) return this;
+ RemoveEntry(entry);
+ return Shrink(key);
+ }
+
+ // Key is already in table, just overwrite value.
+ if (entry != kNotFound) {
+ set(EntryToIndex(entry) + 1, value);
+ return this;
+ }
+
+ // Check whether the hash table should be extended.
+ Object* obj;
+ { MaybeObject* maybe_obj = EnsureCapacity(1, key);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ ObjectHashTable* table = ObjectHashTable::cast(obj);
+ table->AddEntry(table->FindInsertionEntry(hash), key, value);
+ return table;
+}
+
+
+void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) {
+ set(EntryToIndex(entry), key);
+ set(EntryToIndex(entry) + 1, value);
+ ElementAdded();
+}
+
+
+void ObjectHashTable::RemoveEntry(int entry) {
+ Object* null_value = GetHeap()->null_value();
+ set(EntryToIndex(entry), null_value);
+ set(EntryToIndex(entry) + 1, null_value);
+ ElementRemoved();
+}
+
+
#ifdef ENABLE_DEBUGGER_SUPPORT
// Check if there is a break point at this code position.
bool DebugInfo::HasBreakPoint(int code_position) {
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698