diff options
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r-- | deps/v8/src/objects.cc | 1541 |
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 |