summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r--deps/v8/src/objects.cc1541
1 files changed, 560 insertions, 981 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 5c863855f8..65d5d5f528 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -20,17 +20,16 @@
#include "src/compiler.h"
#include "src/cpu-profiler.h"
#include "src/date.h"
-#include "src/debug.h"
+#include "src/debug/debug.h"
#include "src/deoptimizer.h"
#include "src/elements.h"
#include "src/execution.h"
#include "src/field-index-inl.h"
#include "src/field-index.h"
-#include "src/full-codegen.h"
-#include "src/heap/mark-compact.h"
-#include "src/heap/objects-visiting-inl.h"
+#include "src/full-codegen/full-codegen.h"
#include "src/hydrogen.h"
#include "src/ic/ic.h"
+#include "src/interpreter/bytecodes.h"
#include "src/log.h"
#include "src/lookup.h"
#include "src/macro-assembler.h"
@@ -73,16 +72,17 @@ MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
Handle<Context> native_context) {
if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
Handle<JSFunction> constructor;
- if (object->IsNumber()) {
+ if (object->IsSmi()) {
constructor = handle(native_context->number_function(), isolate);
- } else if (object->IsBoolean()) {
- constructor = handle(native_context->boolean_function(), isolate);
- } else if (object->IsString()) {
- constructor = handle(native_context->string_function(), isolate);
- } else if (object->IsSymbol()) {
- constructor = handle(native_context->symbol_function(), isolate);
} else {
- return MaybeHandle<JSReceiver>();
+ int constructor_function_index =
+ Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
+ if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
+ return MaybeHandle<JSReceiver>();
+ }
+ constructor = handle(
+ JSFunction::cast(native_context->get(constructor_function_index)),
+ isolate);
}
Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
Handle<JSValue>::cast(result)->set_value(*object);
@@ -97,11 +97,29 @@ bool Object::BooleanValue() {
if (IsUndetectableObject()) return false; // Undetectable object is false.
if (IsString()) return String::cast(this)->length() != 0;
if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
- if (IsFloat32x4()) return true; // Simd value types always evaluate to true.
+ if (IsSimd128Value()) return true; // Simd value types evaluate to true.
return true;
}
+bool Object::StrictEquals(Object* that) {
+ if (this->IsNumber()) {
+ if (!that->IsNumber()) return false;
+ double const x = this->Number();
+ double const y = that->Number();
+ // Must check explicitly for NaN:s on Windows, but -0 works fine.
+ return x == y && !std::isnan(x) && !std::isnan(y);
+ } else if (this->IsString()) {
+ if (!that->IsString()) return false;
+ return String::cast(this)->Equals(String::cast(that));
+ } else if (this->IsSimd128Value()) {
+ if (!that->IsSimd128Value()) return false;
+ return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
+ }
+ return this == that;
+}
+
+
bool Object::IsCallable() const {
const Object* fun = this;
while (fun->IsJSFunctionProxy()) {
@@ -465,7 +483,8 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
}
-static bool FindAllCanReadHolder(LookupIterator* it) {
+// static
+bool JSObject::AllCanRead(LookupIterator* it) {
// Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
// which have already been checked.
DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
@@ -487,7 +506,7 @@ static bool FindAllCanReadHolder(LookupIterator* it) {
MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
LookupIterator* it) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
- while (FindAllCanReadHolder(it)) {
+ while (AllCanRead(it)) {
if (it->state() == LookupIterator::ACCESSOR) {
return GetPropertyWithAccessor(it, SLOPPY);
}
@@ -507,7 +526,7 @@ MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
LookupIterator* it) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
- while (FindAllCanReadHolder(it)) {
+ while (AllCanRead(it)) {
if (it->state() == LookupIterator::ACCESSOR) {
return Just(it->property_details().attributes());
}
@@ -523,7 +542,8 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
}
-static bool FindAllCanWriteHolder(LookupIterator* it) {
+// static
+bool JSObject::AllCanWrite(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
if (it->state() == LookupIterator::ACCESSOR) {
Handle<Object> accessors = it->GetAccessors();
@@ -539,7 +559,7 @@ static bool FindAllCanWriteHolder(LookupIterator* it) {
MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
LookupIterator* it, Handle<Object> value) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
- if (FindAllCanWriteHolder(it)) {
+ if (AllCanWrite(it)) {
// The supplied language-mode is ignored by SetPropertyWithAccessor.
return SetPropertyWithAccessor(it, value, SLOPPY);
}
@@ -596,33 +616,36 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
}
+bool Object::HasInPrototypeChain(Isolate* isolate, Object* target) {
+ PrototypeIterator iter(isolate, this, PrototypeIterator::START_AT_RECEIVER);
+ while (true) {
+ iter.AdvanceIgnoringProxies();
+ if (iter.IsAtEnd()) return false;
+ if (iter.IsAtEnd(target)) return true;
+ }
+}
+
+
Map* Object::GetRootMap(Isolate* isolate) {
DisallowHeapAllocation no_alloc;
if (IsSmi()) {
- Context* context = isolate->context()->native_context();
- return context->number_function()->initial_map();
+ Context* native_context = isolate->context()->native_context();
+ return native_context->number_function()->initial_map();
}
- HeapObject* heap_object = HeapObject::cast(this);
-
- // The object is either a number, a string, a boolean,
+ // The object is either a number, a string, a symbol, a boolean, a SIMD value,
// a real JS object, or a Harmony proxy.
+ HeapObject* heap_object = HeapObject::cast(this);
if (heap_object->IsJSReceiver()) {
return heap_object->map();
}
- Context* context = isolate->context()->native_context();
-
- if (heap_object->IsHeapNumber()) {
- return context->number_function()->initial_map();
- }
- if (heap_object->IsString()) {
- return context->string_function()->initial_map();
- }
- if (heap_object->IsSymbol()) {
- return context->symbol_function()->initial_map();
- }
- if (heap_object->IsBoolean()) {
- return context->boolean_function()->initial_map();
+ int constructor_function_index =
+ heap_object->map()->GetConstructorFunctionIndex();
+ if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
+ Context* native_context = isolate->context()->native_context();
+ JSFunction* constructor_function =
+ JSFunction::cast(native_context->get(constructor_function_index));
+ return constructor_function->initial_map();
}
return isolate->heap()->null_value()->map();
}
@@ -639,7 +662,7 @@ Object* Object::GetHash() {
Object* Object::GetSimpleHash() {
// The object is either a Smi, a HeapNumber, a name, an odd-ball,
- // a real JS object, or a Harmony proxy.
+ // a SIMD value type, a real JS object, or a Harmony proxy.
if (IsSmi()) {
uint32_t hash = ComputeIntegerHash(Smi::cast(this)->value(), kZeroHashSeed);
return Smi::FromInt(hash & Smi::kMaxValue);
@@ -662,6 +685,10 @@ Object* Object::GetSimpleHash() {
uint32_t hash = Oddball::cast(this)->to_string()->Hash();
return Smi::FromInt(hash);
}
+ if (IsSimd128Value()) {
+ uint32_t hash = Simd128Value::cast(this)->Hash();
+ return Smi::FromInt(hash & Smi::kMaxValue);
+ }
DCHECK(IsJSReceiver());
JSReceiver* receiver = JSReceiver::cast(this);
return receiver->GetHeap()->undefined_value();
@@ -685,15 +712,36 @@ bool Object::SameValue(Object* other) {
if (IsNumber() && other->IsNumber()) {
double this_value = Number();
double other_value = other->Number();
- bool equal = this_value == other_value;
// SameValue(NaN, NaN) is true.
- if (!equal) return std::isnan(this_value) && std::isnan(other_value);
+ if (this_value != other_value) {
+ return std::isnan(this_value) && std::isnan(other_value);
+ }
// SameValue(0.0, -0.0) is false.
- return (this_value != 0) || ((1 / this_value) == (1 / other_value));
+ return (std::signbit(this_value) == std::signbit(other_value));
}
if (IsString() && other->IsString()) {
return String::cast(this)->Equals(String::cast(other));
}
+ if (IsSimd128Value() && other->IsSimd128Value()) {
+ if (IsFloat32x4() && other->IsFloat32x4()) {
+ Float32x4* a = Float32x4::cast(this);
+ Float32x4* b = Float32x4::cast(other);
+ for (int i = 0; i < 4; i++) {
+ float x = a->get_lane(i);
+ float y = b->get_lane(i);
+ // Implements the ES5 SameValue operation for floating point types.
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
+ if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
+ if (std::signbit(x) != std::signbit(y)) return false;
+ }
+ return true;
+ } else {
+ Simd128Value* a = Simd128Value::cast(this);
+ Simd128Value* b = Simd128Value::cast(other);
+ return a->map()->instance_type() == b->map()->instance_type() &&
+ a->BitwiseEquals(b);
+ }
+ }
return false;
}
@@ -707,12 +755,32 @@ bool Object::SameValueZero(Object* other) {
double this_value = Number();
double other_value = other->Number();
// +0 == -0 is true
- return this_value == other_value
- || (std::isnan(this_value) && std::isnan(other_value));
+ return this_value == other_value ||
+ (std::isnan(this_value) && std::isnan(other_value));
}
if (IsString() && other->IsString()) {
return String::cast(this)->Equals(String::cast(other));
}
+ if (IsSimd128Value() && other->IsSimd128Value()) {
+ if (IsFloat32x4() && other->IsFloat32x4()) {
+ Float32x4* a = Float32x4::cast(this);
+ Float32x4* b = Float32x4::cast(other);
+ for (int i = 0; i < 4; i++) {
+ float x = a->get_lane(i);
+ float y = b->get_lane(i);
+ // Implements the ES6 SameValueZero operation for floating point types.
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
+ if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
+ // SameValueZero doesn't distinguish between 0 and -0.
+ }
+ return true;
+ } else {
+ Simd128Value* a = Simd128Value::cast(this);
+ Simd128Value* b = Simd128Value::cast(other);
+ return a->map()->instance_type() == b->map()->instance_type() &&
+ a->BitwiseEquals(b);
+ }
+ }
return false;
}
@@ -861,8 +929,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
self->set_resource(resource);
if (is_internalized) self->Hash(); // Force regeneration of the hash value.
- heap->AdjustLiveBytes(this->address(), new_size - size,
- Heap::CONCURRENT_TO_SWEEPER);
+ heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
return true;
}
@@ -922,8 +989,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
self->set_resource(resource);
if (is_internalized) self->Hash(); // Force regeneration of the hash value.
- heap->AdjustLiveBytes(this->address(), new_size - size,
- Heap::CONCURRENT_TO_SWEEPER);
+ heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
return true;
}
@@ -1250,14 +1316,13 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
case BYTE_ARRAY_TYPE:
os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
break;
+ case BYTECODE_ARRAY_TYPE:
+ os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
+ break;
case FREE_SPACE_TYPE:
os << "<FreeSpace[" << FreeSpace::cast(this)->Size() << "]>";
break;
#define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ARRAY_TYPE: \
- os << "<External" #Type "Array[" \
- << External##Type##Array::cast(this)->length() << "]>"; \
- break; \
case FIXED_##TYPE##_ARRAY_TYPE: \
os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
<< "]>"; \
@@ -1268,7 +1333,7 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
case SHARED_FUNCTION_INFO_TYPE: {
SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
- SmartArrayPointer<char> debug_name =
+ base::SmartArrayPointer<char> debug_name =
shared->DebugName()->ToCString();
if (debug_name[0] != 0) {
os << "<SharedFunctionInfo " << debug_name.get() << ">";
@@ -1324,10 +1389,15 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
os << '>';
break;
}
- case FLOAT32X4_TYPE: {
- os << "<Float32x4: ";
- Float32x4::cast(this)->Float32x4Print(os);
- os << ">";
+ case SIMD128_VALUE_TYPE: {
+#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
+ if (Is##Type()) { \
+ os << "<" #Type ">"; \
+ break; \
+ }
+ SIMD128_TYPES(SIMD128_TYPE)
+#undef SIMD128_TYPE
+ UNREACHABLE();
break;
}
case JS_PROXY_TYPE:
@@ -1380,155 +1450,53 @@ void HeapObject::Iterate(ObjectVisitor* v) {
}
-void HeapObject::IterateBody(InstanceType type, int object_size,
- ObjectVisitor* v) {
- // Avoiding <Type>::cast(this) because it accesses the map pointer field.
- // During GC, the map pointer field is encoded.
- if (type < FIRST_NONSTRING_TYPE) {
- switch (type & kStringRepresentationMask) {
- case kSeqStringTag:
- break;
- case kConsStringTag:
- ConsString::BodyDescriptor::IterateBody(this, v);
- break;
- case kSlicedStringTag:
- SlicedString::BodyDescriptor::IterateBody(this, v);
- break;
- case kExternalStringTag:
- if ((type & kStringEncodingMask) == kOneByteStringTag) {
- reinterpret_cast<ExternalOneByteString*>(this)
- ->ExternalOneByteStringIterateBody(v);
- } else {
- reinterpret_cast<ExternalTwoByteString*>(this)->
- ExternalTwoByteStringIterateBody(v);
- }
- break;
- }
- return;
- }
+bool HeapNumber::HeapNumberBooleanValue() {
+ return DoubleToBoolean(value());
+}
- switch (type) {
- case FIXED_ARRAY_TYPE:
- FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
- break;
- case FIXED_DOUBLE_ARRAY_TYPE:
- break;
- case JS_OBJECT_TYPE:
- case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
- case JS_GENERATOR_OBJECT_TYPE:
- case JS_MODULE_TYPE:
- case JS_VALUE_TYPE:
- case JS_DATE_TYPE:
- case JS_ARRAY_TYPE:
- case JS_TYPED_ARRAY_TYPE:
- case JS_DATA_VIEW_TYPE:
- case JS_SET_TYPE:
- case JS_MAP_TYPE:
- case JS_SET_ITERATOR_TYPE:
- case JS_MAP_ITERATOR_TYPE:
- case JS_WEAK_MAP_TYPE:
- case JS_WEAK_SET_TYPE:
- case JS_REGEXP_TYPE:
- case JS_GLOBAL_PROXY_TYPE:
- case JS_GLOBAL_OBJECT_TYPE:
- case JS_BUILTINS_OBJECT_TYPE:
- case JS_MESSAGE_OBJECT_TYPE:
- JSObject::BodyDescriptor::IterateBody(this, object_size, v);
- break;
- case JS_ARRAY_BUFFER_TYPE:
- JSArrayBuffer::JSArrayBufferIterateBody(this, v);
- break;
- case JS_FUNCTION_TYPE:
- reinterpret_cast<JSFunction*>(this)
- ->JSFunctionIterateBody(object_size, v);
- break;
- case ODDBALL_TYPE:
- Oddball::BodyDescriptor::IterateBody(this, v);
- break;
- case JS_PROXY_TYPE:
- JSProxy::BodyDescriptor::IterateBody(this, v);
- break;
- case JS_FUNCTION_PROXY_TYPE:
- JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
- break;
- case FOREIGN_TYPE:
- reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
- break;
- case MAP_TYPE:
- Map::BodyDescriptor::IterateBody(this, v);
- break;
- case CODE_TYPE:
- reinterpret_cast<Code*>(this)->CodeIterateBody(v);
- break;
- case CELL_TYPE:
- Cell::BodyDescriptor::IterateBody(this, v);
- break;
- case PROPERTY_CELL_TYPE:
- PropertyCell::BodyDescriptor::IterateBody(this, v);
- break;
- case WEAK_CELL_TYPE:
- WeakCell::BodyDescriptor::IterateBody(this, v);
- break;
- case SYMBOL_TYPE:
- Symbol::BodyDescriptor::IterateBody(this, v);
- break;
- case HEAP_NUMBER_TYPE:
- case MUTABLE_HEAP_NUMBER_TYPE:
- case FLOAT32X4_TYPE:
- case FILLER_TYPE:
- case BYTE_ARRAY_TYPE:
- case FREE_SPACE_TYPE:
- break;
+void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
+ os << value();
+}
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ARRAY_TYPE: \
- break; \
- \
- case FIXED_##TYPE##_ARRAY_TYPE: \
- reinterpret_cast<FixedTypedArrayBase*>(this) \
- ->FixedTypedArrayBaseIterateBody(v); \
- break;
+#define FIELD_ADDR_CONST(p, offset) \
+ (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
+#define READ_INT32_FIELD(p, offset) \
+ (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
- case SHARED_FUNCTION_INFO_TYPE: {
- SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
- break;
- }
+#define READ_INT64_FIELD(p, offset) \
+ (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
-#define MAKE_STRUCT_CASE(NAME, Name, name) \
- case NAME##_TYPE:
- STRUCT_LIST(MAKE_STRUCT_CASE)
-#undef MAKE_STRUCT_CASE
- if (type == ALLOCATION_SITE_TYPE) {
- AllocationSite::BodyDescriptor::IterateBody(this, v);
- } else {
- StructBodyDescriptor::IterateBody(this, object_size, v);
- }
- break;
- default:
- PrintF("Unknown type: %d\n", type);
- UNREACHABLE();
- }
-}
+#define READ_BYTE_FIELD(p, offset) \
+ (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
-bool HeapNumber::HeapNumberBooleanValue() {
- return DoubleToBoolean(value());
+bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
+ return READ_INT64_FIELD(this, kValueOffset) ==
+ READ_INT64_FIELD(other, kValueOffset) &&
+ READ_INT64_FIELD(this, kValueOffset + kInt64Size) ==
+ READ_INT64_FIELD(other, kValueOffset + kInt64Size);
}
-void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
- os << value();
+uint32_t Simd128Value::Hash() const {
+ uint32_t seed = v8::internal::kZeroHashSeed;
+ uint32_t hash;
+ hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed);
+ hash = ComputeIntegerHash(
+ READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31);
+ hash = ComputeIntegerHash(
+ READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31);
+ hash = ComputeIntegerHash(
+ READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31);
+ return hash;
}
-void Float32x4::Float32x4Print(std::ostream& os) { // NOLINT
- os << get_lane(0) << ", " << get_lane(1) << ", " << get_lane(2) << ", "
- << get_lane(3);
+void Simd128Value::CopyBits(void* destination) const {
+ memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size);
}
@@ -1748,11 +1716,11 @@ bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
// If no fields were added, and no inobject properties were removed, setting
// the map is sufficient.
- if (target_inobject == inobject_properties()) return false;
+ if (target_inobject == GetInObjectProperties()) return false;
// In-object slack tracking may have reduced the object size of the new map.
// In that case, succeed if all existing fields were inobject, and they still
// fit within the new inobject size.
- DCHECK(target_inobject < inobject_properties());
+ DCHECK(target_inobject < GetInObjectProperties());
if (target_number_of_fields <= target_inobject) {
DCHECK(target_number_of_fields + target_unused == target_inobject);
return false;
@@ -1859,7 +1827,7 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
Handle<Map> old_map(object->map());
int old_number_of_fields;
int number_of_fields = new_map->NumberOfFields();
- int inobject = new_map->inobject_properties();
+ int inobject = new_map->GetInObjectProperties();
int unused = new_map->unused_property_fields();
// Nothing to do if no functions were converted to fields and no smis were
@@ -1895,9 +1863,10 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
DCHECK(number_of_fields == old_number_of_fields + 1);
// This migration is a transition from a map that has run out of property
// space. Therefore it could be done by extending the backing store.
+ int grow_by = external - object->properties()->length();
Handle<FixedArray> old_storage = handle(object->properties(), isolate);
Handle<FixedArray> new_storage =
- FixedArray::CopySize(old_storage, external);
+ isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
// Properly initialize newly added property.
Handle<Object> value;
@@ -2027,7 +1996,7 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
Address address = object->address();
heap->CreateFillerObjectAt(
address + new_instance_size, instance_size_delta);
- heap->AdjustLiveBytes(address, -instance_size_delta,
+ heap->AdjustLiveBytes(*object, -instance_size_delta,
Heap::CONCURRENT_TO_SWEEPER);
}
@@ -2255,10 +2224,23 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
}
+bool FieldTypeIsCleared(Representation rep, Handle<HeapType> type) {
+ return type->Is(HeapType::None()) && rep.IsHeapObject();
+}
+
+
// static
-Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> type1,
+Handle<HeapType> Map::GeneralizeFieldType(Representation rep1,
+ Handle<HeapType> type1,
+ Representation rep2,
Handle<HeapType> type2,
Isolate* isolate) {
+ // Cleared field types need special treatment. They represent lost knowledge,
+ // so we must be conservative, so their generalization with any other type
+ // is "Any".
+ if (FieldTypeIsCleared(rep1, type1) || FieldTypeIsCleared(rep2, type2)) {
+ return HeapType::Any(isolate);
+ }
if (type1->NowIs(type2)) return type2;
if (type2->NowIs(type1)) return type1;
return HeapType::Any(isolate);
@@ -2279,10 +2261,13 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
isolate);
if (old_representation.Equals(new_representation) &&
+ !FieldTypeIsCleared(new_representation, new_field_type) &&
+ // Checking old_field_type for being cleared is not necessary because
+ // the NowIs check below would fail anyway in that case.
new_field_type->NowIs(old_field_type)) {
- DCHECK(Map::GeneralizeFieldType(old_field_type,
- new_field_type,
- isolate)->NowIs(old_field_type));
+ DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type,
+ new_representation, new_field_type, isolate)
+ ->NowIs(old_field_type));
return;
}
@@ -2291,17 +2276,10 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
Handle<DescriptorArray> descriptors(
field_owner->instance_descriptors(), isolate);
DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
- bool old_field_type_was_cleared =
- old_field_type->Is(HeapType::None()) && old_representation.IsHeapObject();
- // Determine the generalized new field type. Conservatively assume type Any
- // for cleared field types because the cleared type could have been a
- // deprecated map and there still could be live instances with a non-
- // deprecated version of the map.
new_field_type =
- old_field_type_was_cleared
- ? HeapType::Any(isolate)
- : Map::GeneralizeFieldType(old_field_type, new_field_type, isolate);
+ Map::GeneralizeFieldType(old_representation, old_field_type,
+ new_representation, new_field_type, isolate);
PropertyDetails details = descriptors->GetDetails(modify_index);
Handle<Name> name(descriptors->GetKey(modify_index));
@@ -2525,8 +2503,10 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
Handle<HeapType> old_field_type =
GetFieldType(isolate, old_descriptors, i,
old_details.location(), tmp_representation);
- next_field_type =
- GeneralizeFieldType(next_field_type, old_field_type, isolate);
+ Representation old_representation = old_details.representation();
+ next_field_type = GeneralizeFieldType(
+ old_representation, old_field_type, new_representation,
+ next_field_type, isolate);
}
} else {
Handle<HeapType> old_field_type =
@@ -2690,21 +2670,24 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
Handle<HeapType> next_field_type;
if (modify_index == i) {
- next_field_type =
- GeneralizeFieldType(target_field_type, new_field_type, isolate);
+ next_field_type = GeneralizeFieldType(
+ target_details.representation(), target_field_type,
+ new_representation, new_field_type, isolate);
if (!property_kind_reconfiguration) {
Handle<HeapType> old_field_type =
GetFieldType(isolate, old_descriptors, i,
old_details.location(), next_representation);
- next_field_type =
- GeneralizeFieldType(next_field_type, old_field_type, isolate);
+ next_field_type = GeneralizeFieldType(
+ old_details.representation(), old_field_type,
+ next_representation, next_field_type, isolate);
}
} else {
Handle<HeapType> old_field_type =
GetFieldType(isolate, old_descriptors, i, old_details.location(),
next_representation);
- next_field_type =
- GeneralizeFieldType(target_field_type, old_field_type, isolate);
+ next_field_type = GeneralizeFieldType(
+ old_details.representation(), old_field_type, next_representation,
+ target_field_type, isolate);
}
Handle<Object> wrapped_type(WrapType(next_field_type));
DataDescriptor d(target_key, current_offset, wrapped_type,
@@ -2765,8 +2748,9 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
Handle<HeapType> old_field_type =
GetFieldType(isolate, old_descriptors, i,
old_details.location(), next_representation);
- next_field_type =
- GeneralizeFieldType(next_field_type, old_field_type, isolate);
+ next_field_type = GeneralizeFieldType(
+ old_details.representation(), old_field_type,
+ next_representation, next_field_type, isolate);
}
} else {
Handle<HeapType> old_field_type =
@@ -3293,8 +3277,7 @@ MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
Handle<Object> to_assign = value;
// Convert the incoming value to a number for storing into typed arrays.
- if (it->IsElement() && (receiver->HasExternalArrayElements() ||
- receiver->HasFixedTypedArrayElements())) {
+ if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
if (!value->IsNumber() && !value->IsUndefined()) {
ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), to_assign,
Execution::ToNumber(it->isolate(), value),
@@ -3329,6 +3312,11 @@ MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
Object);
}
+#if VERIFY_HEAP
+ if (FLAG_verify_heap) {
+ receiver->JSObjectVerify();
+ }
+#endif
return value;
}
@@ -3412,13 +3400,11 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
}
if (FLAG_trace_external_array_abuse &&
- (array->HasExternalArrayElements() ||
- array->HasFixedTypedArrayElements())) {
+ array->HasFixedTypedArrayElements()) {
CheckArrayAbuse(array, "typed elements write", it->index(), true);
}
- if (FLAG_trace_js_array_abuse && !array->HasExternalArrayElements() &&
- !array->HasFixedTypedArrayElements()) {
+ if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
CheckArrayAbuse(array, "elements write", it->index(), false);
}
}
@@ -3453,6 +3439,11 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
it->factory()->the_hole_value()),
Object);
}
+#if VERIFY_HEAP
+ if (FLAG_verify_heap) {
+ receiver->JSObjectVerify();
+ }
+#endif
}
return value;
@@ -3635,19 +3626,6 @@ Handle<Map> Map::FindTransitionedMap(Handle<Map> map,
static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
Map* current_map = map;
- // Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data
- // allows to change elements from arbitrary kind to any ExternalArray
- // elements kind. Satisfy its requirements, checking whether we already
- // have the cached transition.
- if (IsExternalArrayElementsKind(to_kind) &&
- !IsFixedTypedArrayElementsKind(map->elements_kind())) {
- Map* next_map = map->ElementsTransitionMap();
- if (next_map != NULL && next_map->elements_kind() == to_kind) {
- return next_map;
- }
- return map;
- }
-
ElementsKind kind = map->elements_kind();
while (kind != to_kind) {
Map* next_map = current_map->ElementsTransitionMap();
@@ -4018,7 +3996,7 @@ Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
Handle<Object> error = isolate->factory()->NewTypeError(
MessageTemplate::kProxyPropNotConfigurable, handler, name, trap);
isolate->Throw(*error);
- return Just(NONE);
+ return Nothing<PropertyAttributes>();
}
int attributes = NONE;
@@ -4081,7 +4059,8 @@ MaybeHandle<Object> JSProxy::CallTrap(Handle<JSProxy> proxy,
void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
- DCHECK(object->map()->inobject_properties() == map->inobject_properties());
+ DCHECK(object->map()->GetInObjectProperties() ==
+ map->GetInObjectProperties());
ElementsKind obj_kind = object->map()->elements_kind();
ElementsKind map_kind = map->elements_kind();
if (map_kind != obj_kind) {
@@ -4109,6 +4088,11 @@ void JSObject::MigrateInstance(Handle<JSObject> object) {
if (FLAG_trace_migration) {
object->PrintInstanceMigration(stdout, *original_map, *map);
}
+#if VERIFY_HEAP
+ if (FLAG_verify_heap) {
+ object->JSObjectVerify();
+ }
+#endif
}
@@ -4125,6 +4109,11 @@ bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
if (FLAG_trace_migration) {
object->PrintInstanceMigration(stdout, *original_map, object->map());
}
+#if VERIFY_HEAP
+ if (FLAG_verify_heap) {
+ object->JSObjectVerify();
+ }
+#endif
return true;
}
@@ -4177,7 +4166,9 @@ MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
case LookupIterator::ACCESS_CHECK:
if (!it->HasAccess()) {
- return SetPropertyWithFailedAccessCheck(it, value);
+ it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
+ return value;
}
break;
@@ -4228,16 +4219,9 @@ MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
ExecutableAccessorInfo::ClearSetter(new_data);
}
- if (it->IsElement()) {
- SetElementCallback(it->GetHolder<JSObject>(), it->index(), new_data,
- attributes);
- } else {
- SetPropertyCallback(it->GetHolder<JSObject>(), it->name(), new_data,
- attributes);
- }
+ it->TransitionToAccessorPair(new_data, attributes);
} else {
it->ReconfigureDataProperty(value, attributes);
- it->WriteDataValue(value);
}
if (is_observed) {
@@ -4264,8 +4248,7 @@ MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
// Special case: properties of typed arrays cannot be reconfigured to
// non-writable nor to non-enumerable.
- if (it->IsElement() && (object->HasExternalArrayElements() ||
- object->HasFixedTypedArrayElements())) {
+ if (it->IsElement() && object->HasFixedTypedArrayElements()) {
return RedefineNonconfigurableProperty(it->isolate(), it->GetName(),
value, STRICT);
}
@@ -4274,7 +4257,6 @@ MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
if (is_observed) old_value = it->GetDataValue();
it->ReconfigureDataProperty(value, attributes);
- it->WriteDataValue(value);
if (is_observed) {
if (old_value->SameValue(*value)) {
@@ -4586,7 +4568,7 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
Heap* heap = isolate->heap();
heap->CreateFillerObjectAt(object->address() + new_instance_size,
instance_size_delta);
- heap->AdjustLiveBytes(object->address(), -instance_size_delta,
+ heap->AdjustLiveBytes(*object, -instance_size_delta,
Heap::CONCURRENT_TO_SWEEPER);
}
@@ -4598,7 +4580,7 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
// Ensure that in-object space of slow-mode object does not contain random
// garbage.
- int inobject_properties = new_map->inobject_properties();
+ int inobject_properties = new_map->GetInObjectProperties();
for (int i = 0; i < inobject_properties; i++) {
FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
object->RawFastPropertyAtPut(index, Smi::FromInt(0));
@@ -4655,7 +4637,7 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Handle<Map> old_map(object->map(), isolate);
- int inobject_props = old_map->inobject_properties();
+ int inobject_props = old_map->GetInObjectProperties();
// Allocate new map.
Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
@@ -4781,9 +4763,8 @@ void JSObject::ResetElements(Handle<JSObject> object) {
static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
- Handle<FixedArrayBase> array,
- int length,
- Handle<SeededNumberDictionary> dictionary) {
+ Handle<FixedArrayBase> array, int length,
+ Handle<SeededNumberDictionary> dictionary, bool used_as_prototype) {
Isolate* isolate = array->GetIsolate();
Factory* factory = isolate->factory();
bool has_double_elements = array->IsFixedDoubleArray();
@@ -4802,49 +4783,66 @@ static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
}
if (!value->IsTheHole()) {
PropertyDetails details = PropertyDetails::Empty();
- dictionary =
- SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details);
+ dictionary = SeededNumberDictionary::AddNumberEntry(
+ dictionary, i, value, details, used_as_prototype);
}
}
return dictionary;
}
+void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
+ if (dictionary->requires_slow_elements()) return;
+ dictionary->set_requires_slow_elements();
+ // TODO(verwaest): Remove this hack.
+ if (map()->is_prototype_map()) {
+ GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
+ }
+}
+
+
+Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary(
+ Handle<JSObject> object, Handle<FixedArrayBase> elements) {
+ DCHECK(!object->HasDictionaryElements());
+ DCHECK(!object->HasSlowArgumentsElements());
+ Isolate* isolate = object->GetIsolate();
+ // Ensure that notifications fire if the array or object prototypes are
+ // normalizing.
+ isolate->UpdateArrayProtectorOnNormalizeElements(object);
+ int length = object->IsJSArray()
+ ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
+ : elements->length();
+ int used = object->GetFastElementsUsage();
+ Handle<SeededNumberDictionary> dictionary =
+ SeededNumberDictionary::New(isolate, used);
+ return CopyFastElementsToDictionary(elements, length, dictionary,
+ object->map()->is_prototype_map());
+}
+
+
Handle<SeededNumberDictionary> JSObject::NormalizeElements(
Handle<JSObject> object) {
- DCHECK(!object->HasExternalArrayElements() &&
- !object->HasFixedTypedArrayElements());
+ DCHECK(!object->HasFixedTypedArrayElements());
Isolate* isolate = object->GetIsolate();
// Find the backing store.
- Handle<FixedArrayBase> array(FixedArrayBase::cast(object->elements()));
- bool is_arguments =
- (array->map() == isolate->heap()->sloppy_arguments_elements_map());
+ Handle<FixedArrayBase> elements(object->elements(), isolate);
+ bool is_arguments = object->HasSloppyArgumentsElements();
if (is_arguments) {
- array = handle(FixedArrayBase::cast(
- Handle<FixedArray>::cast(array)->get(1)));
+ FixedArray* parameter_map = FixedArray::cast(*elements);
+ elements = handle(FixedArrayBase::cast(parameter_map->get(1)), isolate);
+ }
+
+ if (elements->IsDictionary()) {
+ return Handle<SeededNumberDictionary>::cast(elements);
}
- if (array->IsDictionary()) return Handle<SeededNumberDictionary>::cast(array);
DCHECK(object->HasFastSmiOrObjectElements() ||
object->HasFastDoubleElements() ||
object->HasFastArgumentsElements());
- // Ensure that notifications fire if the array or object prototypes are
- // normalizing.
- isolate->UpdateArrayProtectorOnNormalizeElements(object);
-
- // Compute the effective length and allocate a new backing store.
- int length = object->IsJSArray()
- ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
- : array->length();
- int old_capacity = 0;
- int used_elements = 0;
- object->GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Handle<SeededNumberDictionary> dictionary =
- SeededNumberDictionary::New(isolate, used_elements);
-
- dictionary = CopyFastElementsToDictionary(array, length, dictionary);
+ GetNormalizedElementDictionary(object, elements);
// Switch to using the dictionary as the backing storage for elements.
ElementsKind target_kind =
@@ -5236,14 +5234,6 @@ MaybeHandle<Object> JSReceiver::DeleteProperty(LookupIterator* it,
return it->factory()->false_value();
}
- Handle<JSObject> holder = it->GetHolder<JSObject>();
- // TODO(verwaest): Remove this temporary compatibility hack when blink
- // tests are updated.
- if (!holder.is_identical_to(receiver) &&
- !(receiver->IsJSGlobalProxy() && holder->IsJSGlobalObject())) {
- return it->factory()->true_value();
- }
-
it->Delete();
if (is_observed) {
@@ -5337,7 +5327,6 @@ bool JSObject::ReferencesObject(Object* obj) {
// Raw pixels and external arrays do not reference other
// objects.
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
break;
@@ -5447,8 +5436,7 @@ MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
}
// It's not possible to seal objects with external array elements
- if (object->HasExternalArrayElements() ||
- object->HasFixedTypedArrayElements()) {
+ if (object->HasFixedTypedArrayElements()) {
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray),
Object);
@@ -5459,7 +5447,7 @@ MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
// Make sure that we never go back to fast case.
- dictionary->set_requires_slow_elements();
+ object->RequireSlowElements(*dictionary);
// Do a map transition, other objects with this map may still
// be extensible.
@@ -5492,30 +5480,6 @@ bool JSObject::IsExtensible() {
}
-Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary(
- Handle<JSObject> object) {
- DCHECK(!object->elements()->IsDictionary());
- Isolate* isolate = object->GetIsolate();
- int length = object->IsJSArray()
- ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
- : object->elements()->length();
- if (length > 0) {
- int capacity = 0;
- int used = 0;
- object->GetElementsCapacityAndUsage(&capacity, &used);
- Handle<SeededNumberDictionary> new_element_dictionary =
- SeededNumberDictionary::New(isolate, used);
-
- // Move elements to a dictionary; avoid calling NormalizeElements to avoid
- // unnecessary transitions.
- return CopyFastElementsToDictionary(handle(object->elements()), length,
- new_element_dictionary);
- }
- // No existing elements, use a pre-allocated empty backing store
- return isolate->factory()->empty_slow_element_dictionary();
-}
-
-
template <typename Dictionary>
static void ApplyAttributesToDictionary(Dictionary* dictionary,
const PropertyAttributes attributes) {
@@ -5565,17 +5529,22 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
}
// It's not possible to seal or freeze objects with external array elements
- if (object->HasExternalArrayElements() ||
- object->HasFixedTypedArrayElements()) {
+ if (object->HasFixedTypedArrayElements()) {
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray),
Object);
}
Handle<SeededNumberDictionary> new_element_dictionary;
- if (!object->elements()->IsDictionary()) {
- new_element_dictionary = GetNormalizedElementDictionary(object);
- isolate->UpdateArrayProtectorOnNormalizeElements(object);
+ if (!object->HasDictionaryElements()) {
+ int length =
+ object->IsJSArray()
+ ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
+ : object->elements()->length();
+ new_element_dictionary =
+ length == 0 ? isolate->factory()->empty_slow_element_dictionary()
+ : GetNormalizedElementDictionary(
+ object, handle(object->elements()));
}
Handle<Symbol> transition_marker;
@@ -5632,7 +5601,7 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
SeededNumberDictionary* dictionary = object->element_dictionary();
// Make sure we never go back to the fast case
- dictionary->set_requires_slow_elements();
+ object->RequireSlowElements(dictionary);
if (attrs != NONE) {
ApplyAttributesToDictionary(dictionary, attrs);
}
@@ -5829,7 +5798,7 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
// Deep copy own elements.
// Pixel elements cannot be created using an object literal.
- DCHECK(!copy->HasExternalArrayElements());
+ DCHECK(!copy->HasFixedTypedArrayElements());
switch (kind) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
@@ -5891,7 +5860,6 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
TYPED_ARRAYS(TYPED_ARRAY_CASE)
@@ -6142,10 +6110,13 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
Handle<JSFunction> arguments_function(
JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
+ PrototypeIterator::WhereToEnd end = type == OWN_ONLY
+ ? PrototypeIterator::END_AT_NON_HIDDEN
+ : PrototypeIterator::END_AT_NULL;
// Only collect keys if access is permitted.
for (PrototypeIterator iter(isolate, object,
PrototypeIterator::START_AT_RECEIVER);
- !iter.IsAtEnd(); iter.Advance()) {
+ !iter.IsAtEnd(end); iter.Advance()) {
if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
Handle<JSProxy> proxy(JSProxy::cast(*PrototypeIterator::GetCurrent(iter)),
isolate);
@@ -6172,8 +6143,10 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
// Check access rights if required.
if (current->IsAccessCheckNeeded() && !isolate->MayAccess(current)) {
- isolate->ReportFailedAccessCheck(current);
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
+ if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
+ isolate->ReportFailedAccessCheck(current);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
+ }
break;
}
@@ -6234,123 +6207,34 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
}
DCHECK(ContainsOnlyValidKeys(content));
}
-
- // If we only want own properties we bail out after the first
- // iteration.
- if (type == OWN_ONLY) break;
}
return content;
}
-// Try to update an accessor in an elements dictionary. Return true if the
-// update succeeded, and false otherwise.
-static bool UpdateGetterSetterInDictionary(
- SeededNumberDictionary* dictionary,
- uint32_t index,
- Object* getter,
- Object* setter,
- PropertyAttributes attributes) {
- int entry = dictionary->FindEntry(index);
- if (entry != SeededNumberDictionary::kNotFound) {
- Object* result = dictionary->ValueAt(entry);
- PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == ACCESSOR_CONSTANT && result->IsAccessorPair()) {
- DCHECK(details.IsConfigurable());
- if (details.attributes() != attributes) {
- dictionary->DetailsAtPut(
- entry, PropertyDetails(attributes, ACCESSOR_CONSTANT, index,
- PropertyCellType::kNoCell));
- }
- AccessorPair::cast(result)->SetComponents(getter, setter);
- return true;
- }
- }
- return false;
-}
-
-
-void JSObject::DefineElementAccessor(Handle<JSObject> object,
- uint32_t index,
- Handle<Object> getter,
- Handle<Object> setter,
- PropertyAttributes attributes) {
- switch (object->GetElementsKind()) {
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- break;
-
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ELEMENTS: \
- case TYPE##_ELEMENTS: \
-
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
- // Ignore getters and setters on pixel and external array elements.
- return;
-
- case DICTIONARY_ELEMENTS:
- if (UpdateGetterSetterInDictionary(object->element_dictionary(),
- index,
- *getter,
- *setter,
- attributes)) {
- return;
- }
- break;
- case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
- case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
- // Ascertain whether we have read-only properties or an existing
- // getter/setter pair in an arguments elements dictionary backing
- // store.
- FixedArray* parameter_map = FixedArray::cast(object->elements());
- uint32_t length = parameter_map->length();
- Object* probe =
- index < (length - 2) ? parameter_map->get(index + 2) : NULL;
- if (probe == NULL || probe->IsTheHole()) {
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- if (arguments->IsDictionary()) {
- SeededNumberDictionary* dictionary =
- SeededNumberDictionary::cast(arguments);
- if (UpdateGetterSetterInDictionary(dictionary,
- index,
- *getter,
- *setter,
- attributes)) {
- return;
- }
- }
- }
- break;
- }
- }
-
- Isolate* isolate = object->GetIsolate();
- Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
- accessors->SetComponents(*getter, *setter);
-
- SetElementCallback(object, index, accessors, attributes);
-}
-
-
bool Map::DictionaryElementsInPrototypeChainOnly() {
if (IsDictionaryElementsKind(elements_kind())) {
return false;
}
for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
- if (iter.GetCurrent()->IsJSProxy()) {
- // Be conservative, don't walk into proxies.
+ // Be conservative, don't walk into proxies.
+ if (iter.GetCurrent()->IsJSProxy()) return true;
+ // String wrappers have non-configurable, non-writable elements.
+ if (iter.GetCurrent()->IsStringWrapper()) return true;
+ JSObject* current = JSObject::cast(iter.GetCurrent());
+
+ if (current->HasDictionaryElements() &&
+ current->element_dictionary()->requires_slow_elements()) {
return true;
}
- if (IsDictionaryElementsKind(
- JSObject::cast(iter.GetCurrent())->map()->elements_kind())) {
- return true;
+ if (current->HasSlowArgumentsElements()) {
+ FixedArray* parameter_map = FixedArray::cast(current->elements());
+ Object* arguments = parameter_map->get(1);
+ if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
+ return true;
+ }
}
}
@@ -6358,66 +6242,6 @@ bool Map::DictionaryElementsInPrototypeChainOnly() {
}
-void JSObject::SetElementCallback(Handle<JSObject> object,
- uint32_t index,
- Handle<Object> structure,
- PropertyAttributes attributes) {
- Heap* heap = object->GetHeap();
- PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0,
- PropertyCellType::kNoCell);
-
- // Normalize elements to make this operation simple.
- bool had_dictionary_elements = object->HasDictionaryElements();
- Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
- DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
- // Update the dictionary with the new ACCESSOR_CONSTANT property.
- dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
- details);
- dictionary->set_requires_slow_elements();
-
- // Update the dictionary backing store on the object.
- if (object->elements()->map() == heap->sloppy_arguments_elements_map()) {
- // Also delete any parameter alias.
- //
- // TODO(kmillikin): when deleting the last parameter alias we could
- // switch to a direct backing store without the parameter map. This
- // would allow GC of the context.
- FixedArray* parameter_map = FixedArray::cast(object->elements());
- if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
- parameter_map->set(index + 2, heap->the_hole_value());
- }
- parameter_map->set(1, *dictionary);
- } else {
- object->set_elements(*dictionary);
-
- if (!had_dictionary_elements) {
- // KeyedStoreICs (at least the non-generic ones) need a reset.
- heap->ClearAllICsByKind(Code::KEYED_STORE_IC);
- }
- }
-}
-
-
-void JSObject::SetPropertyCallback(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> structure,
- PropertyAttributes attributes) {
- PropertyNormalizationMode mode = object->map()->is_prototype_map()
- ? KEEP_INOBJECT_PROPERTIES
- : CLEAR_INOBJECT_PROPERTIES;
- // Normalize object to make this operation simple.
- NormalizeProperties(object, mode, 0, "SetPropertyCallback");
-
-
- // Update the dictionary with the new ACCESSOR_CONSTANT property.
- PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0,
- PropertyCellType::kMutable);
- SetNormalizedProperty(object, name, structure, details);
-
- ReoptimizeIfPrototype(object);
-}
-
-
MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> getter,
@@ -6425,13 +6249,6 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
PropertyAttributes attributes) {
Isolate* isolate = object->GetIsolate();
- // Make sure that the top context does not change when doing callbacks or
- // interceptor calls.
- AssertNoContextChange ncc(isolate);
-
- // Try to flatten before operating on the string.
- if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
-
LookupIterator it = LookupIterator::PropertyOrElement(
isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
@@ -6444,6 +6261,11 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
it.Next();
}
+ // Ignore accessors on typed arrays.
+ if (it.IsElement() && object->HasFixedTypedArrayElements()) {
+ return it.factory()->undefined_value();
+ }
+
Handle<Object> old_value = isolate->factory()->the_hole_value();
bool is_observed = object->map()->is_observed() &&
!isolate->IsInternallyUsedPropertyName(name);
@@ -6457,25 +6279,20 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
}
}
- if (it.IsElement()) {
- DefineElementAccessor(it.GetStoreTarget(), it.index(), getter, setter,
- attributes);
- } else {
- DCHECK(getter->IsSpecFunction() || getter->IsUndefined() ||
- getter->IsNull());
- DCHECK(setter->IsSpecFunction() || setter->IsUndefined() ||
- setter->IsNull());
- // At least one of the accessors needs to be a new value.
- DCHECK(!getter->IsNull() || !setter->IsNull());
- if (!getter->IsNull()) {
- it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
- }
- if (!setter->IsNull()) {
- it.TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
- }
+ DCHECK(getter->IsSpecFunction() || getter->IsUndefined() || getter->IsNull());
+ DCHECK(setter->IsSpecFunction() || setter->IsUndefined() || setter->IsNull());
+ // At least one of the accessors needs to be a new value.
+ DCHECK(!getter->IsNull() || !setter->IsNull());
+ if (!getter->IsNull()) {
+ it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
+ }
+ if (!setter->IsNull()) {
+ it.TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
}
if (is_observed) {
+ // Make sure the top context isn't changed.
+ AssertNoContextChange ncc(isolate);
const char* type = preexists ? "reconfigure" : "add";
RETURN_ON_EXCEPTION(
isolate, EnqueueChangeRecord(object, type, name, old_value), Object);
@@ -6488,14 +6305,7 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
Handle<AccessorInfo> info) {
Isolate* isolate = object->GetIsolate();
-
- // Make sure that the top context does not change when doing callbacks or
- // interceptor calls.
- AssertNoContextChange ncc(isolate);
-
- // Try to flatten before operating on the string.
- Handle<Name> name(Name::cast(info->name()));
- if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
+ Handle<Name> name(Name::cast(info->name()), isolate);
LookupIterator it = LookupIterator::PropertyOrElement(
isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
@@ -6514,25 +6324,20 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
it.Next();
}
+ // Ignore accessors on typed arrays.
+ if (it.IsElement() && object->HasFixedTypedArrayElements()) {
+ return it.factory()->undefined_value();
+ }
+
CHECK(GetPropertyAttributes(&it).IsJust());
// ES5 forbids turning a property into an accessor if it's not
// configurable. See 8.6.1 (Table 5).
- if (it.IsFound() && (it.IsReadOnly() || !it.IsConfigurable())) {
- return it.factory()->undefined_value();
- }
-
- // Ignore accessors on typed arrays.
- if (it.IsElement() && (object->HasFixedTypedArrayElements() ||
- object->HasExternalArrayElements())) {
+ if (it.IsFound() && !it.IsConfigurable()) {
return it.factory()->undefined_value();
}
- if (it.IsElement()) {
- SetElementCallback(object, it.index(), info, info->property_attributes());
- } else {
- SetPropertyCallback(object, name, info, info->property_attributes());
- }
+ it.TransitionToAccessorPair(info, info->property_attributes());
return object;
}
@@ -6720,13 +6525,13 @@ Handle<Map> Map::CopyNormalized(Handle<Map> map,
PropertyNormalizationMode mode) {
int new_instance_size = map->instance_size();
if (mode == CLEAR_INOBJECT_PROPERTIES) {
- new_instance_size -= map->inobject_properties() * kPointerSize;
+ new_instance_size -= map->GetInObjectProperties() * kPointerSize;
}
Handle<Map> result = RawCopy(map, new_instance_size);
if (mode != CLEAR_INOBJECT_PROPERTIES) {
- result->set_inobject_properties(map->inobject_properties());
+ result->SetInObjectProperties(map->GetInObjectProperties());
}
result->set_dictionary_map(true);
@@ -6744,11 +6549,9 @@ Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
Handle<Map> result = RawCopy(map, map->instance_size());
// Please note instance_type and instance_size are set when allocated.
- result->set_inobject_properties(map->inobject_properties());
+ result->SetInObjectProperties(map->GetInObjectProperties());
result->set_unused_property_fields(map->unused_property_fields());
- result->set_pre_allocated_property_fields(
- map->pre_allocated_property_fields());
result->ClearCodeCache(map->GetHeap());
map->NotifyLeafMapLayoutChange();
return result;
@@ -6773,8 +6576,7 @@ Handle<Map> Map::ShareDescriptor(Handle<Map> map,
if (old_size == 0) {
descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
} else {
- int slack = SlackForArraySize(map->is_prototype_map(), old_size,
- kMaxNumberOfDescriptors);
+ int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
EnsureDescriptorSlack(map, slack);
descriptors = handle(map->instance_descriptors());
}
@@ -6940,13 +6742,10 @@ Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
Map* maybe_elements_transition_map = NULL;
if (flag == INSERT_TRANSITION) {
maybe_elements_transition_map = map->ElementsTransitionMap();
- DCHECK(
- maybe_elements_transition_map == NULL ||
- ((maybe_elements_transition_map->elements_kind() ==
- DICTIONARY_ELEMENTS ||
- IsExternalArrayElementsKind(
- maybe_elements_transition_map->elements_kind())) &&
- (kind == DICTIONARY_ELEMENTS || IsExternalArrayElementsKind(kind))));
+ DCHECK(maybe_elements_transition_map == NULL ||
+ (maybe_elements_transition_map->elements_kind() ==
+ DICTIONARY_ELEMENTS &&
+ kind == DICTIONARY_ELEMENTS));
DCHECK(!IsFastElementsKind(kind) ||
IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
DCHECK(kind != map->elements_kind());
@@ -7062,7 +6861,7 @@ Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
JSObject::kHeaderSize + kPointerSize * inobject_properties;
// Adjust the map with the extra inobject properties.
- copy->set_inobject_properties(inobject_properties);
+ copy->SetInObjectProperties(inobject_properties);
copy->set_unused_property_fields(inobject_properties);
copy->set_instance_size(new_instance_size);
copy->set_visitor_id(StaticVisitorBase::GetVisitorId(*copy));
@@ -7132,43 +6931,6 @@ bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
// static
-Handle<Map> Map::PrepareForDataElement(Handle<Map> map, Handle<Object> value) {
- ElementsKind kind = map->elements_kind();
- bool holey = IsHoleyElementsKind(kind);
-
- switch (kind) {
- case FAST_SMI_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- if (value->IsSmi()) return map;
- kind = value->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS;
- break;
-
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- if (value->IsNumber()) return map;
- kind = FAST_ELEMENTS;
- break;
-
- case FAST_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
- case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ELEMENTS: \
- case TYPE##_ELEMENTS:
-
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
- return map;
- }
-
- if (holey) kind = GetHoleyElementsKind(kind);
- return Map::AsElementsKind(map, kind);
-}
-
-
-// static
Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
Handle<Object> value) {
// Dictionaries can store any property value.
@@ -7280,12 +7042,7 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
Isolate* isolate = name->GetIsolate();
// Dictionary maps can always have additional data properties.
- if (map->is_dictionary_map()) {
- // For global objects, property cells are inlined. We need to change the
- // map.
- if (map->IsGlobalObjectMap()) return Copy(map, "GlobalAccessor");
- return map;
- }
+ if (map->is_dictionary_map()) return map;
// Migrate to the newest map before transitioning to the new property.
map = Update(map);
@@ -7602,10 +7359,11 @@ void CodeCache::UpdateDefaultCache(
// Extend the code cache with some new entries (at least one). Must be a
// multiple of the entry size.
- int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
+ Isolate* isolate = cache->GetIsolate();
+ int new_length = length + (length >> 1) + kCodeCacheEntrySize;
new_length = new_length - new_length % kCodeCacheEntrySize;
DCHECK((new_length % kCodeCacheEntrySize) == 0);
- cache = FixedArray::CopySize(cache, new_length);
+ cache = isolate->factory()->CopyFixedArrayAndGrow(cache, new_length - length);
// Add the (name, code) pair to the new cache.
cache->set(length + kCodeCacheEntryNameOffset, *name);
@@ -7998,27 +7756,6 @@ MaybeHandle<FixedArray> FixedArray::UnionOfKeys(Handle<FixedArray> first,
}
-Handle<FixedArray> FixedArray::CopySize(
- Handle<FixedArray> array, int new_length, PretenureFlag pretenure) {
- Isolate* isolate = array->GetIsolate();
- if (new_length == 0) return isolate->factory()->empty_fixed_array();
- Handle<FixedArray> result =
- isolate->factory()->NewFixedArray(new_length, pretenure);
- // Copy the content
- DisallowHeapAllocation no_gc;
- int len = array->length();
- if (new_length < len) len = new_length;
- // We are taking the map from the old fixed array so the map is sure to
- // be an immortal immutable object.
- result->set_map_no_write_barrier(array->map());
- WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
- for (int i = 0; i < len; i++) {
- result->set(i, array->get(i), mode);
- }
- return result;
-}
-
-
void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
@@ -8152,28 +7889,22 @@ Handle<WeakFixedArray> WeakFixedArray::Allocate(
DCHECK(0 <= size);
Handle<FixedArray> result =
isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
- Handle<WeakFixedArray> casted_result = Handle<WeakFixedArray>::cast(result);
- if (initialize_from.is_null()) {
- for (int i = 0; i < result->length(); ++i) {
- result->set(i, Smi::FromInt(0));
- }
- } else {
+ int index = 0;
+ if (!initialize_from.is_null()) {
DCHECK(initialize_from->Length() <= size);
Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
- int target_index = kFirstIndex;
- for (int source_index = kFirstIndex; source_index < raw_source->length();
- ++source_index) {
- // The act of allocating might have caused entries in the source array
- // to be cleared. Copy only what's needed.
- if (initialize_from->IsEmptySlot(source_index - kFirstIndex)) continue;
- result->set(target_index++, raw_source->get(source_index));
- }
- casted_result->set_last_used_index(target_index - 1 - kFirstIndex);
- for (; target_index < result->length(); ++target_index) {
- result->set(target_index, Smi::FromInt(0));
+ // Copy the entries without compacting, since the PrototypeInfo relies on
+ // the index of the entries not to change.
+ while (index < raw_source->length()) {
+ result->set(index, raw_source->get(index));
+ index++;
}
}
- return casted_result;
+ while (index < result->length()) {
+ result->set(index, Smi::FromInt(0));
+ index++;
+ }
+ return Handle<WeakFixedArray>::cast(result);
}
@@ -8209,9 +7940,12 @@ Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
int capacity = array->length();
bool empty = (capacity == 0);
if (capacity < kFirstIndex + length) {
- capacity = kFirstIndex + length;
- capacity = capacity + Max(capacity / 2, 2);
- array = Handle<ArrayList>::cast(FixedArray::CopySize(array, capacity));
+ Isolate* isolate = array->GetIsolate();
+ int new_capacity = kFirstIndex + length;
+ new_capacity = new_capacity + Max(new_capacity / 2, 2);
+ int grow_by = new_capacity - capacity;
+ array = Handle<ArrayList>::cast(
+ isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
if (empty) array->SetLength(0);
}
return array;
@@ -8469,13 +8203,12 @@ String::FlatContent String::GetFlatContent() {
}
-SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robust_flag,
- int offset,
- int length,
- int* length_return) {
+base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robust_flag,
+ int offset, int length,
+ int* length_return) {
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return SmartArrayPointer<char>(NULL);
+ return base::SmartArrayPointer<char>(NULL);
}
// Negative length means the to the end of the string.
if (length < 0) length = kMaxInt - offset;
@@ -8512,13 +8245,13 @@ SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
last = character;
}
result[utf8_byte_position] = 0;
- return SmartArrayPointer<char>(result);
+ return base::SmartArrayPointer<char>(result);
}
-SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robust_flag,
- int* length_return) {
+base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robust_flag,
+ int* length_return) {
return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
}
@@ -8544,9 +8277,10 @@ const uc16* String::GetTwoByteData(unsigned start) {
}
-SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
+base::SmartArrayPointer<uc16> String::ToWideCString(
+ RobustnessFlag robust_flag) {
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return SmartArrayPointer<uc16>();
+ return base::SmartArrayPointer<uc16>();
}
StringCharacterStream stream(this);
@@ -8558,7 +8292,7 @@ SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
result[i++] = character;
}
result[i] = 0;
- return SmartArrayPointer<uc16>(result);
+ return base::SmartArrayPointer<uc16>(result);
}
@@ -9344,7 +9078,7 @@ Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
// that are a multiple of pointer size.
heap->CreateFillerObjectAt(start_of_string + new_size, delta);
}
- heap->AdjustLiveBytes(start_of_string, -delta, Heap::CONCURRENT_TO_SWEEPER);
+ heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER);
// We are storing the new length using release store after creating a filler
// for the left-over space to avoid races with the sweeper thread.
@@ -9515,10 +9249,10 @@ bool Map::EquivalentToForTransition(Map* other) {
bool Map::EquivalentToForNormalization(Map* other,
PropertyNormalizationMode mode) {
- int properties = mode == CLEAR_INOBJECT_PROPERTIES
- ? 0 : other->inobject_properties();
+ int properties =
+ mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
- inobject_properties() == properties;
+ GetInObjectProperties() == properties;
}
@@ -9531,11 +9265,32 @@ void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
}
+bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
+ DisallowHeapAllocation no_gc;
+ if (shared() == candidate) return true;
+ if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
+ DeoptimizationInputData* const data =
+ DeoptimizationInputData::cast(code()->deoptimization_data());
+ if (data->length() == 0) return false;
+ FixedArray* const literals = data->LiteralArray();
+ int const inlined_count = data->InlinedFunctionCount()->value();
+ for (int i = 0; i < inlined_count; ++i) {
+ if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
void JSFunction::MarkForOptimization() {
Isolate* isolate = GetIsolate();
+ // Do not optimize if function contains break points.
+ if (shared()->HasDebugInfo()) return;
DCHECK(!IsOptimized());
DCHECK(shared()->allows_lazy_compilation() ||
!shared()->optimization_disabled());
+ DCHECK(!shared()->HasDebugInfo());
set_code_no_write_barrier(
isolate->builtins()->builtin(Builtins::kCompileOptimized));
// No write barrier required, since the builtin is part of the root set.
@@ -9615,6 +9370,7 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
Handle<FixedArray> literals,
BailoutId osr_ast_id) {
Isolate* isolate = shared->GetIsolate();
+ DCHECK(!shared->SearchOptimizedCodeMap(*native_context, osr_ast_id).code);
DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
DCHECK(native_context->IsNativeContext());
STATIC_ASSERT(kEntryLength == 4);
@@ -9624,20 +9380,18 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
if (value->IsSmi()) {
// No optimized code map.
DCHECK_EQ(0, Smi::cast(*value)->value());
- new_code_map = isolate->factory()->NewFixedArray(kInitialLength);
+ new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
old_length = kEntriesStart;
} else {
- // Copy old map and append one new entry.
+ // Copy old optimized code map and append one new entry.
Handle<FixedArray> old_code_map = Handle<FixedArray>::cast(value);
- DCHECK(!shared->SearchOptimizedCodeMap(*native_context, osr_ast_id).code);
+ new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
+ old_code_map, kEntryLength, TENURED);
old_length = old_code_map->length();
- new_code_map = FixedArray::CopySize(
- old_code_map, old_length + kEntryLength);
- // Zap the old map for the sake of the heap verifier.
- if (Heap::ShouldZapGarbage()) {
- Object** data = old_code_map->data_start();
- MemsetPointer(data, isolate->heap()->the_hole_value(), old_length);
- }
+ // Zap the old map to avoid any stale entries. Note that this is required
+ // for correctness because entries are being treated weakly by the GC.
+ MemsetPointer(old_code_map->data_start(), isolate->heap()->the_hole_value(),
+ old_length);
}
new_code_map->set(old_length + kContextOffset, *native_context);
new_code_map->set(old_length + kCachedCodeOffset, *code);
@@ -9724,7 +9478,10 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
// Always trim even when array is cleared because of heap verifier.
GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
length - dst);
- if (code_map->length() == kEntriesStart) ClearOptimizedCodeMap();
+ if (code_map->length() == kEntriesStart &&
+ code_map->get(kSharedCodeIndex)->IsUndefined()) {
+ ClearOptimizedCodeMap();
+ }
}
}
@@ -9736,7 +9493,8 @@ void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
// Always trim even when array is cleared because of heap verifier.
GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map,
shrink_by);
- if (code_map->length() == kEntriesStart) {
+ if (code_map->length() == kEntriesStart &&
+ code_map->get(kSharedCodeIndex)->IsUndefined()) {
ClearOptimizedCodeMap();
}
}
@@ -9752,7 +9510,7 @@ static void GetMinInobjectSlack(Map* map, void* data) {
static void ShrinkInstanceSize(Map* map, void* data) {
int slack = *reinterpret_cast<int*>(data);
- map->set_inobject_properties(map->inobject_properties() - slack);
+ map->SetInObjectProperties(map->GetInObjectProperties() - slack);
map->set_unused_property_fields(map->unused_property_fields() - slack);
map->set_instance_size(map->instance_size() - slack * kPointerSize);
@@ -10234,7 +9992,7 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
} else {
prototype = isolate->factory()->NewFunctionPrototype(function);
}
- map->set_inobject_properties(in_object_properties);
+ map->SetInObjectProperties(in_object_properties);
map->set_unused_property_fields(in_object_properties);
DCHECK(map->has_fast_object_elements());
@@ -10253,7 +10011,7 @@ void JSFunction::SetInstanceClassName(String* name) {
void JSFunction::PrintName(FILE* out) {
- SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
+ base::SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
PrintF(out, "%s", name.get());
}
@@ -10304,15 +10062,16 @@ Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
}
-void Oddball::Initialize(Isolate* isolate,
- Handle<Oddball> oddball,
- const char* to_string,
- Handle<Object> to_number,
- byte kind) {
+void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
+ const char* to_string, Handle<Object> to_number,
+ const char* type_of, byte kind) {
Handle<String> internalized_to_string =
isolate->factory()->InternalizeUtf8String(to_string);
- oddball->set_to_string(*internalized_to_string);
+ Handle<String> internalized_type_of =
+ isolate->factory()->InternalizeUtf8String(type_of);
oddball->set_to_number(*to_number);
+ oddball->set_to_string(*internalized_to_string);
+ oddball->set_type_of(*internalized_type_of);
oddball->set_kind(kind);
}
@@ -10659,8 +10418,8 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
if (lit->dont_optimize_reason() != kNoReason) {
shared_info->DisableOptimization(lit->dont_optimize_reason());
}
- shared_info->set_dont_crankshaft(
- lit->flags()->Contains(AstPropertiesFlag::kDontCrankshaft));
+ shared_info->set_dont_crankshaft(lit->flags() &
+ AstProperties::kDontCrankshaft);
shared_info->set_kind(lit->kind());
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_asm_function(lit->scope()->asm_function());
@@ -10798,11 +10557,9 @@ void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
- DCHECK((RelocInfo::IsJSReturn(rinfo->rmode()) &&
- rinfo->IsPatchedReturnSequence()) ||
- (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
- rinfo->IsPatchedDebugBreakSlotSequence()));
- Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
+ DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
+ rinfo->IsPatchedDebugBreakSlotSequence());
+ Object* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
Object* old_target = target;
VisitPointer(&target);
CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
@@ -10846,7 +10603,7 @@ void Code::InvalidateEmbeddedObjects() {
void Code::Relocate(intptr_t delta) {
for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
- it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
+ it.rinfo()->apply(delta);
}
CpuFeatures::FlushICache(instruction_start(), instruction_size());
}
@@ -10899,7 +10656,7 @@ void Code::CopyFrom(const CodeDesc& desc) {
Code* code = Code::cast(*p);
it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
} else {
- it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
+ it.rinfo()->apply(delta);
}
}
CpuFeatures::FlushICache(instruction_start(), instruction_size());
@@ -11826,6 +11583,26 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
#endif // ENABLE_DISASSEMBLER
+void BytecodeArray::Disassemble(std::ostream& os) {
+ os << "Frame size " << frame_size() << "\n";
+ Vector<char> buf = Vector<char>::New(50);
+
+ const uint8_t* first_bytecode_address = GetFirstBytecodeAddress();
+ int bytecode_size = 0;
+ for (int i = 0; i < this->length(); i += bytecode_size) {
+ const uint8_t* bytecode_start = &first_bytecode_address[i];
+ interpreter::Bytecode bytecode =
+ interpreter::Bytecodes::FromByte(bytecode_start[0]);
+ bytecode_size = interpreter::Bytecodes::Size(bytecode);
+
+ SNPrintF(buf, "%p", bytecode_start);
+ os << buf.start() << " : ";
+ interpreter::Bytecodes::Decode(os, bytecode_start);
+ os << "\n";
+ }
+}
+
+
// static
void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
DCHECK(capacity >= 0);
@@ -12019,9 +11796,10 @@ Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
Handle<DependentCode> DependentCode::EnsureSpace(
Handle<DependentCode> entries) {
+ Isolate* isolate = entries->GetIsolate();
if (entries->length() == 0) {
entries = Handle<DependentCode>::cast(
- FixedArray::CopySize(entries, kCodesStartIndex + 1, TENURED));
+ isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
for (int g = 0; g < kGroupCount; g++) {
entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
}
@@ -12031,8 +11809,9 @@ Handle<DependentCode> DependentCode::EnsureSpace(
GroupStartIndexes starts(*entries);
int capacity =
kCodesStartIndex + DependentCode::Grow(starts.number_of_entries());
+ int grow_by = capacity - entries->length();
return Handle<DependentCode>::cast(
- FixedArray::CopySize(entries, capacity, TENURED));
+ isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
}
@@ -12365,16 +12144,6 @@ void JSObject::ValidateElements(Handle<JSObject> object) {
}
-// static
-MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
- uint32_t index, Handle<Object> value,
- LanguageMode language_mode) {
- Isolate* isolate = object->GetIsolate();
- LookupIterator it(isolate, object, index);
- return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED);
-}
-
-
static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
uint32_t index,
uint32_t* new_capacity) {
@@ -12395,9 +12164,7 @@ static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
// 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;
- object->GetElementsCapacityAndUsage(&old_capacity, &used_elements);
+ int used_elements = object->GetFastElementsUsage();
int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
SeededNumberDictionary::kEntrySize;
return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
@@ -12764,79 +12531,47 @@ MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) {
}
-void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
- *capacity = 0;
- *used = 0;
+template <typename BackingStore>
+static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
+ int limit = object->IsJSArray()
+ ? Smi::cast(JSArray::cast(object)->length())->value()
+ : store->length();
+ int used = 0;
+ for (int i = 0; i < limit; ++i) {
+ if (!store->is_the_hole(i)) ++used;
+ }
+ return used;
+}
+
- FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
- FixedArray* backing_store = NULL;
+int JSObject::GetFastElementsUsage() {
+ FixedArrayBase* store = elements();
switch (GetElementsKind()) {
- case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
- case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
- backing_store_base =
- FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
- backing_store = FixedArray::cast(backing_store_base);
- if (backing_store->IsDictionary()) {
- SeededNumberDictionary* dictionary =
- SeededNumberDictionary::cast(backing_store);
- *capacity = dictionary->Capacity();
- *used = dictionary->NumberOfElements();
- break;
- }
- // Fall through.
case FAST_SMI_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- if (IsJSArray()) {
- *capacity = backing_store_base->length();
- *used = Smi::cast(JSArray::cast(this)->length())->value();
- break;
- }
- // Fall through if packing is not guaranteed.
+ // Only JSArray have packed elements.
+ return Smi::cast(JSArray::cast(this)->length())->value();
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ store = FixedArray::cast(FixedArray::cast(store)->get(1));
+ // Fall through.
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_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: {
- SeededNumberDictionary* dictionary = element_dictionary();
- *capacity = dictionary->Capacity();
- *used = dictionary->NumberOfElements();
- break;
- }
- case FAST_DOUBLE_ELEMENTS:
- if (IsJSArray()) {
- *capacity = backing_store_base->length();
- *used = Smi::cast(JSArray::cast(this)->length())->value();
- break;
- }
- // Fall through if packing is not guaranteed.
- case FAST_HOLEY_DOUBLE_ELEMENTS: {
- *capacity = elements()->length();
- if (*capacity == 0) break;
- FixedDoubleArray * elms = FixedDoubleArray::cast(elements());
- for (int i = 0; i < *capacity; i++) {
- if (!elms->is_the_hole(i)) ++(*used);
- }
- break;
- }
+ return FastHoleyElementsUsage(this, FixedArray::cast(store));
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ if (elements()->length() == 0) return 0;
+ return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
- {
- // External arrays are considered 100% used.
- FixedArrayBase* external_array = FixedArrayBase::cast(elements());
- *capacity = external_array->length();
- *used = external_array->length();
- break;
- }
+ UNREACHABLE();
}
+ return 0;
}
@@ -13163,10 +12898,11 @@ void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
// Fill in the names of own properties into the supplied storage. The main
// purpose of this function is to provide reflection information for the object
// mirrors.
-void JSObject::GetOwnPropertyNames(
- FixedArray* storage, int index, PropertyAttributes filter) {
+int JSObject::GetOwnPropertyNames(FixedArray* storage, int index,
+ PropertyAttributes filter) {
DCHECK(storage->length() >= (NumberOfOwnProperties(filter) - index));
if (HasFastProperties()) {
+ int start_index = index;
int real_size = map()->NumberOfOwnDescriptors();
DescriptorArray* descs = map()->instance_descriptors();
for (int i = 0; i < real_size; i++) {
@@ -13175,12 +12911,13 @@ void JSObject::GetOwnPropertyNames(
storage->set(index++, descs->GetKey(i));
}
}
+ return index - start_index;
} else if (IsGlobalObject()) {
- global_dictionary()->CopyKeysTo(storage, index, filter,
- GlobalDictionary::UNSORTED);
+ return global_dictionary()->CopyKeysTo(storage, index, filter,
+ GlobalDictionary::UNSORTED);
} else {
- property_dictionary()->CopyKeysTo(storage, index, filter,
- NameDictionary::UNSORTED);
+ return property_dictionary()->CopyKeysTo(storage, index, filter,
+ NameDictionary::UNSORTED);
}
}
@@ -13207,6 +12944,23 @@ int JSObject::NumberOfEnumElements() {
int JSObject::GetOwnElementKeys(FixedArray* storage,
PropertyAttributes filter) {
int counter = 0;
+
+ // If this is a String wrapper, add the string indices first,
+ // as they're guaranteed to preced the elements in numerical order
+ // and ascending order is required by ECMA-262, 6th, 9.1.12.
+ if (IsJSValue()) {
+ Object* val = JSValue::cast(this)->value();
+ if (val->IsString()) {
+ String* str = String::cast(val);
+ if (storage) {
+ for (int i = 0; i < str->length(); i++) {
+ storage->set(counter + i, Smi::FromInt(i));
+ }
+ }
+ counter += str->length();
+ }
+ }
+
switch (GetElementsKind()) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
@@ -13244,7 +12998,6 @@ int JSObject::GetOwnElementKeys(FixedArray* storage,
}
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
TYPED_ARRAYS(TYPED_ARRAY_CASE)
@@ -13263,7 +13016,7 @@ int JSObject::GetOwnElementKeys(FixedArray* storage,
case DICTIONARY_ELEMENTS: {
if (storage != NULL) {
- element_dictionary()->CopyKeysTo(storage, filter,
+ element_dictionary()->CopyKeysTo(storage, counter, filter,
SeededNumberDictionary::SORTED);
}
counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
@@ -13280,7 +13033,7 @@ int JSObject::GetOwnElementKeys(FixedArray* storage,
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(arguments);
if (storage != NULL) {
- dictionary->CopyKeysTo(storage, filter,
+ dictionary->CopyKeysTo(storage, counter, filter,
SeededNumberDictionary::UNSORTED);
}
counter += dictionary->NumberOfElementsFilterAttributes(filter);
@@ -13313,18 +13066,6 @@ int JSObject::GetOwnElementKeys(FixedArray* storage,
}
}
- if (this->IsJSValue()) {
- Object* val = JSValue::cast(this)->value();
- if (val->IsString()) {
- String* str = String::cast(val);
- if (storage) {
- for (int i = 0; i < str->length(); i++) {
- storage->set(counter + i, Smi::FromInt(i));
- }
- }
- counter += str->length();
- }
- }
DCHECK(!storage || storage->length() == counter);
return counter;
}
@@ -13580,9 +13321,7 @@ Handle<Derived> HashTable<Derived, Shape, Key>::New(
int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
? at_least_space_for
- : isolate->creating_default_snapshot()
- ? ComputeCapacityForSerialization(at_least_space_for)
- : ComputeCapacity(at_least_space_for);
+ : ComputeCapacity(at_least_space_for);
if (capacity > HashTable::kMaxCapacity) {
v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
}
@@ -14004,7 +13743,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
return bailout;
} else {
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
- new_dict, pos, value, details);
+ new_dict, pos, value, details, object->map()->is_prototype_map());
DCHECK(result.is_identical_to(new_dict));
USE(result);
pos++;
@@ -14015,7 +13754,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
return bailout;
} else {
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
- new_dict, key, value, details);
+ new_dict, key, value, details, object->map()->is_prototype_map());
DCHECK(result.is_identical_to(new_dict));
USE(result);
}
@@ -14031,7 +13770,8 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
}
HandleScope scope(isolate);
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
- new_dict, pos, isolate->factory()->undefined_value(), no_details);
+ new_dict, pos, isolate->factory()->undefined_value(), no_details,
+ object->map()->is_prototype_map());
DCHECK(result.is_identical_to(new_dict));
USE(result);
pos++;
@@ -14078,8 +13818,7 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
JSObject::ValidateElements(object);
JSObject::SetMapAndElements(object, new_map, fast_elements);
- } else if (object->HasExternalArrayElements() ||
- object->HasFixedTypedArrayElements()) {
+ } else if (object->HasFixedTypedArrayElements()) {
// Typed arrays cannot have holes or undefined elements.
return handle(Smi::FromInt(
FixedArrayBase::cast(object->elements())->length()), isolate);
@@ -14182,7 +13921,6 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
ExternalArrayType JSTypedArray::type() {
switch (elements()->map()->instance_type()) {
#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ARRAY_TYPE: \
case FIXED_##TYPE##_ARRAY_TYPE: \
return kExternal##Type##Array;
@@ -14198,9 +13936,9 @@ ExternalArrayType JSTypedArray::type() {
size_t JSTypedArray::element_size() {
switch (elements()->map()->instance_type()) {
-#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ARRAY_TYPE: \
- return size;
+#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
+ case FIXED_##TYPE##_ARRAY_TYPE: \
+ return size;
TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
@@ -14218,131 +13956,6 @@ void FixedArray::SetValue(uint32_t index, Object* value) { set(index, value); }
void FixedDoubleArray::SetValue(uint32_t index, Object* value) {
set(index, value->Number());
}
-
-
-void ExternalUint8ClampedArray::SetValue(uint32_t index, Object* value) {
- uint8_t clamped_value = 0;
- if (value->IsSmi()) {
- int int_value = Smi::cast(value)->value();
- if (int_value < 0) {
- clamped_value = 0;
- } else if (int_value > 255) {
- clamped_value = 255;
- } else {
- clamped_value = static_cast<uint8_t>(int_value);
- }
- } else if (value->IsHeapNumber()) {
- double double_value = HeapNumber::cast(value)->value();
- if (!(double_value > 0)) {
- // NaN and less than zero clamp to zero.
- clamped_value = 0;
- } else if (double_value > 255) {
- // Greater than 255 clamp to 255.
- clamped_value = 255;
- } else {
- // Other doubles are rounded to the nearest integer.
- clamped_value = static_cast<uint8_t>(lrint(double_value));
- }
- } else {
- // Clamp undefined to zero (default). All other types have been
- // converted to a number type further up in the call chain.
- DCHECK(value->IsUndefined());
- }
- set(index, clamped_value);
-}
-
-
-template <typename ExternalArrayClass, typename ValueType>
-static void ExternalArrayIntSetter(ExternalArrayClass* receiver, uint32_t index,
- Object* value) {
- ValueType cast_value = 0;
- if (value->IsSmi()) {
- int int_value = Smi::cast(value)->value();
- cast_value = static_cast<ValueType>(int_value);
- } else if (value->IsHeapNumber()) {
- double double_value = HeapNumber::cast(value)->value();
- cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
- } else {
- // Clamp undefined to zero (default). All other types have been
- // converted to a number type further up in the call chain.
- DCHECK(value->IsUndefined());
- }
- receiver->set(index, cast_value);
-}
-
-
-void ExternalInt8Array::SetValue(uint32_t index, Object* value) {
- ExternalArrayIntSetter<ExternalInt8Array, int8_t>(this, index, value);
-}
-
-
-void ExternalUint8Array::SetValue(uint32_t index, Object* value) {
- ExternalArrayIntSetter<ExternalUint8Array, uint8_t>(this, index, value);
-}
-
-
-void ExternalInt16Array::SetValue(uint32_t index, Object* value) {
- ExternalArrayIntSetter<ExternalInt16Array, int16_t>(this, index, value);
-}
-
-
-void ExternalUint16Array::SetValue(uint32_t index, Object* value) {
- ExternalArrayIntSetter<ExternalUint16Array, uint16_t>(this, index, value);
-}
-
-
-void ExternalInt32Array::SetValue(uint32_t index, Object* value) {
- ExternalArrayIntSetter<ExternalInt32Array, int32_t>(this, index, value);
-}
-
-
-void ExternalUint32Array::SetValue(uint32_t index, Object* value) {
- uint32_t cast_value = 0;
- if (value->IsSmi()) {
- int int_value = Smi::cast(value)->value();
- cast_value = static_cast<uint32_t>(int_value);
- } else if (value->IsHeapNumber()) {
- double double_value = HeapNumber::cast(value)->value();
- cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
- } else {
- // Clamp undefined to zero (default). All other types have been
- // converted to a number type further up in the call chain.
- DCHECK(value->IsUndefined());
- }
- set(index, cast_value);
-}
-
-
-void ExternalFloat32Array::SetValue(uint32_t index, Object* value) {
- float cast_value = std::numeric_limits<float>::quiet_NaN();
- if (value->IsSmi()) {
- int int_value = Smi::cast(value)->value();
- cast_value = static_cast<float>(int_value);
- } else if (value->IsHeapNumber()) {
- double double_value = HeapNumber::cast(value)->value();
- cast_value = static_cast<float>(double_value);
- } else {
- // Clamp undefined to NaN (default). All other types have been
- // converted to a number type further up in the call chain.
- DCHECK(value->IsUndefined());
- }
- set(index, cast_value);
-}
-
-
-void ExternalFloat64Array::SetValue(uint32_t index, Object* value) {
- double double_value = std::numeric_limits<double>::quiet_NaN();
- if (value->IsNumber()) {
- double_value = value->Number();
- } else {
- // Clamp undefined to NaN (default). All other types have been
- // converted to a number type further up in the call chain.
- DCHECK(value->IsUndefined());
- }
- set(index, double_value);
-}
-
-
void GlobalObject::InvalidatePropertyCell(Handle<GlobalObject> global,
Handle<Name> name) {
DCHECK(!global->HasFastProperties());
@@ -14897,7 +14510,8 @@ void Dictionary<Derived, Shape, Key>::AddEntry(
}
-void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
+void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
+ bool used_as_prototype) {
DisallowHeapAllocation no_allocation;
// If the dictionary requires slow elements an element has already
// been added at a high index.
@@ -14905,6 +14519,10 @@ void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
// Check if this index is high enough that we should require slow
// elements.
if (key > kRequiresSlowElementsLimit) {
+ if (used_as_prototype) {
+ // TODO(verwaest): Remove this hack.
+ GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
+ }
set_requires_slow_elements();
return;
}
@@ -14918,11 +14536,9 @@ void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
- Handle<SeededNumberDictionary> dictionary,
- uint32_t key,
- Handle<Object> value,
- PropertyDetails details) {
- dictionary->UpdateMaxNumberKey(key);
+ Handle<SeededNumberDictionary> dictionary, uint32_t key,
+ Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
+ dictionary->UpdateMaxNumberKey(key, used_as_prototype);
SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
return Add(dictionary, key, value, details);
}
@@ -14938,10 +14554,9 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
- Handle<SeededNumberDictionary> dictionary,
- uint32_t key,
- Handle<Object> value) {
- dictionary->UpdateMaxNumberKey(key);
+ Handle<SeededNumberDictionary> dictionary, uint32_t key,
+ Handle<Object> value, bool used_as_prototype) {
+ dictionary->UpdateMaxNumberKey(key, used_as_prototype);
return AtPut(dictionary, key, value);
}
@@ -14955,13 +14570,11 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
- Handle<SeededNumberDictionary> dictionary,
- uint32_t key,
- Handle<Object> value,
- PropertyDetails details) {
+ Handle<SeededNumberDictionary> dictionary, uint32_t key,
+ Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
int entry = dictionary->FindEntry(key);
if (entry == kNotFound) {
- return AddNumberEntry(dictionary, key, value, details);
+ return AddNumberEntry(dictionary, key, value, details, used_as_prototype);
}
// Preserve enumeration index.
details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
@@ -15020,29 +14633,6 @@ bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
}
-template <typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::CopyKeysTo(
- FixedArray* storage, PropertyAttributes filter,
- typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
- DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
- int capacity = this->Capacity();
- int index = 0;
- for (int i = 0; i < capacity; i++) {
- Object* k = this->KeyAt(i);
- if (this->IsKey(k) && !FilterKey(k, filter)) {
- if (this->IsDeleted(i)) continue;
- PropertyDetails details = this->DetailsAt(i);
- PropertyAttributes attr = details.attributes();
- if ((attr & filter) == 0) storage->set(index++, k);
- }
- }
- if (sort_mode == Dictionary::SORTED) {
- storage->SortPairs(storage, index);
- }
- DCHECK(storage->length() >= index);
-}
-
-
template <typename Dictionary>
struct EnumIndexComparator {
explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
@@ -15082,10 +14672,11 @@ void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(FixedArray* storage) {
template <typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::CopyKeysTo(
+int Dictionary<Derived, Shape, Key>::CopyKeysTo(
FixedArray* storage, int index, PropertyAttributes filter,
typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
+ int start_index = index;
int capacity = this->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = this->KeyAt(i);
@@ -15100,6 +14691,7 @@ void Dictionary<Derived, Shape, Key>::CopyKeysTo(
storage->SortPairs(storage, index);
}
DCHECK(storage->length() >= index);
+ return index - start_index;
}
@@ -15973,21 +15565,6 @@ void JSArrayBuffer::Neuter() {
}
-static ElementsKind FixedToExternalElementsKind(ElementsKind elements_kind) {
- switch (elements_kind) {
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS;
-
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
-
- default:
- UNREACHABLE();
- return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
- }
-}
-
-
Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
Handle<JSTypedArray> typed_array) {
@@ -15996,10 +15573,6 @@ Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
- Handle<Map> new_map = Map::TransitionElementsTo(
- map,
- FixedToExternalElementsKind(map->elements_kind()));
-
Handle<FixedTypedArrayBase> fixed_typed_array(
FixedTypedArrayBase::cast(typed_array->elements()));
@@ -16016,21 +15589,23 @@ Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
memcpy(buffer->backing_store(),
fixed_typed_array->DataPtr(),
fixed_typed_array->DataSize());
- Handle<ExternalArray> new_elements =
- isolate->factory()->NewExternalArray(
+ Handle<FixedTypedArrayBase> new_elements =
+ isolate->factory()->NewFixedTypedArrayWithExternalPointer(
fixed_typed_array->length(), typed_array->type(),
static_cast<uint8_t*>(buffer->backing_store()));
- JSObject::SetMapAndElements(typed_array, new_map, new_elements);
+ typed_array->set_elements(*new_elements);
return buffer;
}
Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
- if (IsExternalArrayElementsKind(map()->elements_kind())) {
- Handle<Object> result(buffer(), GetIsolate());
- return Handle<JSArrayBuffer>::cast(result);
+ Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
+ GetIsolate());
+ if (array_buffer->was_neutered() ||
+ array_buffer->backing_store() != nullptr) {
+ return array_buffer;
}
Handle<JSTypedArray> self(this);
return MaterializeArrayBuffer(self);
@@ -16058,6 +15633,8 @@ Handle<PropertyCell> PropertyCell::InvalidateEntry(
} else {
cell->set_value(isolate->heap()->the_hole_value());
}
+ details = details.set_cell_type(PropertyCellType::kInvalidated);
+ cell->set_property_details(details);
cell->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kPropertyCellChangedGroup);
return new_cell;
@@ -16152,8 +15729,9 @@ void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
cell->set_value(*value);
// Deopt when transitioning from a constant type.
- if (!invalidate && (old_type != new_type)) {
- auto isolate = dictionary->GetIsolate();
+ if (!invalidate && (old_type != new_type ||
+ original_details.IsReadOnly() != details.IsReadOnly())) {
+ Isolate* isolate = dictionary->GetIsolate();
cell->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kPropertyCellChangedGroup);
}
@@ -16170,5 +15748,6 @@ void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
isolate, DependentCode::kPropertyCellChangedGroup);
}
}
+
} // namespace internal
} // namespace v8