// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <sstream>
+
#include "src/v8.h"
#include "src/accessors.h"
}
-bool JSObject::IsDirty() {
- Object* cons_obj = map()->constructor();
- if (!cons_obj->IsJSFunction())
- return true;
- JSFunction* fun = JSFunction::cast(cons_obj);
- if (!fun->shared()->IsApiFunction())
- return true;
- // If the object is fully fast case and has the same map it was
- // created with then no changes can have been made to it.
- return map() != fun->initial_map()
- || !HasFastObjectElements()
- || !HasFastProperties();
-}
-
-
MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
Handle<Object> object,
Handle<Object> receiver,
}
+MaybeHandle<Object> Object::SetElementWithReceiver(
+ Isolate* isolate, Handle<Object> object, Handle<Object> receiver,
+ uint32_t index, Handle<Object> value, StrictMode strict_mode) {
+ // Iterate up the prototype chain until an element is found or the null
+ // prototype is encountered.
+ bool done = false;
+ for (PrototypeIterator iter(isolate, object,
+ object->IsJSProxy() || object->IsJSObject()
+ ? PrototypeIterator::START_AT_RECEIVER
+ : PrototypeIterator::START_AT_PROTOTYPE);
+ !iter.IsAtEnd() && !done; iter.Advance()) {
+ if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
+ // TODO(dslomov): implement.
+ isolate->ThrowIllegalOperation();
+ return MaybeHandle<Object>();
+ }
+
+ Handle<JSObject> js_object =
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+
+ // Check access rights if needed.
+ if (js_object->IsAccessCheckNeeded()) {
+ if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_SET)) {
+ isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_SET);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ return isolate->factory()->undefined_value();
+ }
+ }
+
+ if (js_object->HasIndexedInterceptor()) {
+ Maybe<PropertyAttributes> from_interceptor =
+ JSObject::GetElementAttributeFromInterceptor(js_object, receiver,
+ index);
+ if (!from_interceptor.has_value) return MaybeHandle<Object>();
+ if ((from_interceptor.value & READ_ONLY) != 0) {
+ return WriteToReadOnlyElement(isolate, receiver, index, value,
+ strict_mode);
+ }
+ done = from_interceptor.value != ABSENT;
+ }
+
+ if (!done &&
+ js_object->elements() != isolate->heap()->empty_fixed_array()) {
+ ElementsAccessor* accessor = js_object->GetElementsAccessor();
+ PropertyAttributes attrs =
+ accessor->GetAttributes(receiver, js_object, index);
+ if ((attrs & READ_ONLY) != 0) {
+ return WriteToReadOnlyElement(isolate, receiver, index, value,
+ strict_mode);
+ }
+ Handle<AccessorPair> accessor_pair;
+ if (accessor->GetAccessorPair(receiver, js_object, index)
+ .ToHandle(&accessor_pair)) {
+ return JSObject::SetElementWithCallback(receiver, accessor_pair, index,
+ value, js_object, strict_mode);
+ } else {
+ done = attrs != ABSENT;
+ }
+ }
+ }
+
+ if (!receiver->IsJSObject()) {
+ return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode);
+ }
+ Handle<JSObject> target = Handle<JSObject>::cast(receiver);
+ ElementsAccessor* accessor = target->GetElementsAccessor();
+ PropertyAttributes attrs = accessor->GetAttributes(receiver, target, index);
+ if ((attrs & READ_ONLY) != 0) {
+ return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode);
+ }
+ PropertyAttributes new_attrs = attrs != ABSENT ? attrs : NONE;
+ return JSObject::SetElement(target, index, value, new_attrs, strict_mode,
+ false);
+}
+
+
Map* Object::GetRootMap(Isolate* isolate) {
DisallowHeapAllocation no_alloc;
if (IsSmi()) {
void Object::ShortPrint(StringStream* accumulator) {
- OStringStream os;
+ std::ostringstream os;
os << Brief(this);
- accumulator->Add(os.c_str());
+ accumulator->Add(os.str().c_str());
}
-OStream& operator<<(OStream& os, const Brief& v) {
+std::ostream& operator<<(std::ostream& os, const Brief& v) {
if (v.value->IsSmi()) {
Smi::cast(v.value)->SmiPrint(os);
} else {
}
-void Smi::SmiPrint(OStream& os) const { // NOLINT
+void Smi::SmiPrint(std::ostream& os) const { // NOLINT
os << value();
}
return;
}
- ConsStringIteratorOp op;
- StringCharacterStream stream(this, &op);
+ StringCharacterStream stream(this);
bool truncated = false;
if (len > kMaxShortPrintLength) {
}
-void String::PrintUC16(OStream& os, int start, int end) { // NOLINT
+void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
if (end < 0) end = length();
- ConsStringIteratorOp op;
- StringCharacterStream stream(this, &op, start);
+ StringCharacterStream stream(this, start);
for (int i = start; i < end && stream.HasMore(); i++) {
os << AsUC16(stream.GetNext());
}
}
-void HeapObject::HeapObjectShortPrint(OStream& os) { // NOLINT
+void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
Heap* heap = GetHeap();
if (!heap->Contains(this)) {
os << "!!!INVALID POINTER!!!";
}
case SYMBOL_TYPE: {
Symbol* symbol = Symbol::cast(this);
- os << "<Symbol: " << symbol->Hash();
- if (!symbol->name()->IsUndefined()) {
- os << " ";
- HeapStringAllocator allocator;
- StringStream accumulator(&allocator);
- String::cast(symbol->name())->StringShortPrint(&accumulator);
- os << accumulator.ToCString().get();
- }
- os << ">";
+ symbol->SymbolShortPrint(os);
break;
}
case HEAP_NUMBER_TYPE: {
os << '>';
break;
}
- case FLOAT32x4_TYPE:
- os << "<Float32x4: ";
- Float32x4::cast(this)->Float32x4Print(os);
- os << '>';
- break;
- case FLOAT64x2_TYPE:
- os << "<Float64x2: ";
- Float64x2::cast(this)->Float64x2Print(os);
- os << '>';
- break;
- case INT32x4_TYPE:
- os << "<Int32x4: ";
- Int32x4::cast(this)->Int32x4Print(os);
- os << '>';
- break;
case JS_PROXY_TYPE:
os << "<JSProxy>";
break;
case JS_GLOBAL_OBJECT_TYPE:
case JS_BUILTINS_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
- case FLOAT32x4_TYPE:
- case FLOAT64x2_TYPE:
- case INT32x4_TYPE:
JSObject::BodyDescriptor::IterateBody(this, object_size, v);
break;
case JS_FUNCTION_TYPE:
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;
}
-void HeapNumber::HeapNumberPrint(OStream& os) { // NOLINT
+void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
os << value();
}
-void Float32x4::Float32x4Print(OStream& os) {
- // The Windows version of vsnprintf can allocate when printing a %g string
- // into a buffer that may not be big enough. We don't want random memory
- // allocation when producing post-crash stack traces, so we print into a
- // buffer that is plenty big enough for any floating point number, then
- // print that using vsnprintf (which may truncate but never allocate if
- // there is no more space in the buffer).
- EmbeddedVector<char, 100> buffer;
- SNPrintF(buffer, "%.16g %.16g %.16g %.16g", x(), y(), z(), w());
- os << buffer.start();
-}
-
-
-void Int32x4::Int32x4Print(OStream& os) {
- // The Windows version of vsnprintf can allocate when printing a %g string
- // into a buffer that may not be big enough. We don't want random memory
- // allocation when producing post-crash stack traces, so we print into a
- // buffer that is plenty big enough for any floating point number, then
- // print that using vsnprintf (which may truncate but never allocate if
- // there is no more space in the buffer).
- EmbeddedVector<char, 100> buffer;
- SNPrintF(buffer, "%u %u %u %u", x(), y(), z(), w());
- os << buffer.start();
-}
-
-
-void Float64x2::Float64x2Print(OStream& os) {
- // The Windows version of vsnprintf can allocate when printing a %g string
- // into a buffer that may not be big enough. We don't want random memory
- // allocation when producing post-crash stack traces, so we print into a
- // buffer that is plenty big enough for any floating point number, then
- // print that using vsnprintf (which may truncate but never allocate if
- // there is no more space in the buffer).
- EmbeddedVector<char, 100> buffer;
- SNPrintF(buffer, "%.16g %.16g", x(), y());
- os << buffer.start();
-}
-
-
String* JSReceiver::class_name() {
if (IsJSFunction() || IsJSFunctionProxy()) {
return GetHeap()->Function_string();
}
-void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
- const char* type_str,
- Handle<Name> name,
- Handle<Object> old_value) {
+MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
+ const char* type_str,
+ Handle<Name> name,
+ Handle<Object> old_value) {
DCHECK(!object->IsJSGlobalProxy());
DCHECK(!object->IsJSGlobalObject());
Isolate* isolate = object->GetIsolate();
Handle<Object> args[] = { type, object, name, old_value };
int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
- Execution::Call(isolate,
- Handle<JSFunction>(isolate->observers_notify_change()),
- isolate->factory()->undefined_value(),
- argc, args).Assert();
+ return Execution::Call(isolate,
+ Handle<JSFunction>(isolate->observers_notify_change()),
+ isolate->factory()->undefined_value(), argc, args);
}
case kTagged: return "t";
case kSmi: return "s";
case kDouble: return "d";
- case kFloat32x4: return "float32x4";
- case kFloat64x2: return "float64x2";
- case kInt32x4: return "int32x44";
case kInteger32: return "i";
case kHeapObject: return "h";
case kExternal: return "x";
}
DCHECK(number_of_fields == old_number_of_fields + 1);
- // This migration is a transition from a map that has run out out property
+ // 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.
Handle<FixedArray> old_storage = handle(object->properties(), isolate);
Handle<FixedArray> new_storage =
}
-void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
- int modify_index,
- Representation new_representation,
- Handle<HeapType> new_field_type) {
- Handle<Map> new_map = Map::GeneralizeRepresentation(
- handle(object->map()), modify_index, new_representation, new_field_type,
- FORCE_FIELD);
- MigrateToMap(object, new_map);
-}
-
-
int Map::NumberOfFields() {
DescriptorArray* descriptors = instance_descriptors();
int result = 0;
// Invalidates a transition target at |key|, and installs |new_descriptors| over
// the current instance_descriptors to ensure proper sharing of descriptor
// arrays.
-void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
+// Returns true if the transition target at given key was deprecated.
+bool Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
+ bool transition_target_deprecated = false;
if (HasTransitionArray()) {
TransitionArray* transitions = this->transitions();
int transition = transitions->Search(key);
if (transition != TransitionArray::kNotFound) {
transitions->GetTarget(transition)->DeprecateTransitionTree();
+ transition_target_deprecated = true;
}
}
// Don't overwrite the empty descriptor array.
- if (NumberOfOwnDescriptors() == 0) return;
+ if (NumberOfOwnDescriptors() == 0) return transition_target_deprecated;
DescriptorArray* to_replace = instance_descriptors();
Map* current = this;
}
set_owns_descriptors(false);
+ return transition_target_deprecated;
}
int split_nof = split_map->NumberOfOwnDescriptors();
DCHECK_NE(old_nof, split_nof);
- split_map->DeprecateTarget(
- old_descriptors->GetKey(split_nof), *new_descriptors);
+ bool transition_target_deprecated =
+ split_map->DeprecateTarget(old_descriptors->GetKey(split_nof),
+ *new_descriptors);
+ // If |transition_target_deprecated| is true then the transition array
+ // already contains entry for given descriptor. This means that the transition
+ // could be inserted regardless of whether transitions array is full or not.
+ if (!transition_target_deprecated && !split_map->CanHaveMoreTransitions()) {
+ return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+ "can't have more transitions");
+ }
if (FLAG_trace_generalization) {
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
Handle<Object> value,
StrictMode strict_mode,
- StoreFromKeyed store_mode) {
+ StoreFromKeyed store_mode,
+ StorePropertyMode data_store_mode) {
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc(it->isolate());
Object);
}
+ if (data_store_mode == SUPER_PROPERTY) {
+ LookupIterator own_lookup(it->GetReceiver(), it->name(),
+ LookupIterator::OWN);
+
+ return JSObject::SetProperty(&own_lookup, value, strict_mode, store_mode,
+ NORMAL_PROPERTY);
+ }
+
return AddDataProperty(it, value, NONE, strict_mode, store_mode);
}
}
-Handle<Object> Object::SetDataProperty(LookupIterator* it,
- Handle<Object> value) {
+MaybeHandle<Object> Object::WriteToReadOnlyElement(Isolate* isolate,
+ Handle<Object> receiver,
+ uint32_t index,
+ Handle<Object> value,
+ StrictMode strict_mode) {
+ if (strict_mode != STRICT) return value;
+
+ Handle<Object> args[] = {isolate->factory()->NewNumberFromUint(index),
+ receiver};
+ THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
+ HandleVector(args, arraysize(args))),
+ Object);
+}
+
+
+MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
+ Handle<Object> value) {
// Proxies are handled on the WithHandler path. Other non-JSObjects cannot
// have own properties.
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
// Send the change record if there are observers.
if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
- JSObject::EnqueueChangeRecord(receiver, "update", it->name(),
- maybe_old.ToHandleChecked());
+ RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord(
+ receiver, "update", it->name(),
+ maybe_old.ToHandleChecked()),
+ Object);
}
return value;
// instead. If the prototype is Null, the proxy is detached.
if (receiver->IsJSGlobalProxy()) return value;
+ // If the receiver is Indexed Exotic object (currently only typed arrays),
+ // disallow adding properties with numeric names.
+ if (it->IsSpecialNumericIndex()) return value;
+
// Possibly migrate to the most up-to-date map that will be able to store
// |value| under it->name() with |attributes|.
it->PrepareTransitionToDataProperty(value, attributes, store_mode);
// Send the change record if there are observers.
if (receiver->map()->is_observed() &&
!it->name().is_identical_to(it->factory()->hidden_string())) {
- JSObject::EnqueueChangeRecord(receiver, "add", it->name(),
- it->factory()->the_hole_value());
+ RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord(
+ receiver, "add", it->name(),
+ it->factory()->the_hole_value()),
+ Object);
}
return value;
}
-void JSObject::MigrateToNewProperty(Handle<JSObject> object,
- Handle<Map> map,
- Handle<Object> value) {
- JSObject::MigrateToMap(object, map);
- if (map->GetLastDescriptorDetails().type() != FIELD) return;
- object->WriteToField(map->LastAdded(), *value);
-}
-
-
void JSObject::WriteToField(int descriptor, Object* value) {
DisallowHeapAllocation no_gc;
!Name::Equals(it.isolate()->factory()->prototype_string(),
name) ||
!Handle<JSFunction>::cast(object)->should_have_prototype()) {
- EnqueueChangeRecord(object, "update", name, old_value);
+ RETURN_ON_EXCEPTION(
+ it.isolate(),
+ EnqueueChangeRecord(object, "update", name, old_value),
+ Object);
}
}
return value;
if (old_value->SameValue(*value)) {
old_value = it.isolate()->factory()->the_hole_value();
}
- EnqueueChangeRecord(object, "reconfigure", name, old_value);
+ RETURN_ON_EXCEPTION(
+ it.isolate(),
+ EnqueueChangeRecord(object, "reconfigure", name, old_value),
+ Object);
}
return value;
}
if (old_value->SameValue(*value)) {
old_value = it.isolate()->factory()->the_hole_value();
}
- EnqueueChangeRecord(object, "reconfigure", name, old_value);
+ RETURN_ON_EXCEPTION(
+ it.isolate(),
+ EnqueueChangeRecord(object, "reconfigure", name, old_value),
+ Object);
}
return value;
if (old_value->SameValue(*value)) {
old_value = it.isolate()->factory()->the_hole_value();
}
- EnqueueChangeRecord(object, "reconfigure", name, old_value);
+ RETURN_ON_EXCEPTION(
+ it.isolate(),
+ EnqueueChangeRecord(object, "reconfigure", name, old_value),
+ Object);
}
return value;
// callbacks or interceptor calls.
AssertNoContextChange ncc(isolate);
+ Maybe<PropertyAttributes> from_interceptor =
+ GetElementAttributeFromInterceptor(object, receiver, index);
+ if (!from_interceptor.has_value) return Maybe<PropertyAttributes>();
+ if (from_interceptor.value != ABSENT) return maybe(from_interceptor.value);
+
+ return GetElementAttributeWithoutInterceptor(object, receiver, index,
+ check_prototype);
+}
+
+
+Maybe<PropertyAttributes> JSObject::GetElementAttributeFromInterceptor(
+ Handle<JSObject> object, Handle<Object> receiver, uint32_t index) {
+ Isolate* isolate = object->GetIsolate();
+ AssertNoContextChange ncc(isolate);
+
Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
PropertyCallbackArguments args(
isolate, interceptor->data(), *receiver, *object);
v8::Handle<v8::Value> result = args.Call(getter, index);
if (!result.IsEmpty()) return maybe(NONE);
}
-
- return GetElementAttributeWithoutInterceptor(
- object, receiver, index, check_prototype);
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
+ return maybe(ABSENT);
}
int number_of_elements = dictionary->NumberOfElements();
if (number_of_elements > kMaxNumberOfDescriptors) return;
+ Handle<FixedArray> iteration_order;
if (number_of_elements != dictionary->NextEnumerationIndex()) {
- NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
+ iteration_order =
+ NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
+ } else {
+ iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
}
- int instance_descriptor_length = 0;
+ int instance_descriptor_length = iteration_order->length();
int number_of_fields = 0;
// Compute the length of the instance descriptor.
- int capacity = dictionary->Capacity();
- for (int i = 0; i < capacity; i++) {
- Object* k = dictionary->KeyAt(i);
- if (dictionary->IsKey(k)) {
- Object* value = dictionary->ValueAt(i);
- PropertyType type = dictionary->DetailsAt(i).type();
- DCHECK(type != FIELD);
- instance_descriptor_length++;
- if (type == NORMAL && !value->IsJSFunction()) {
- number_of_fields += 1;
- }
+ for (int i = 0; i < instance_descriptor_length; i++) {
+ int index = Smi::cast(iteration_order->get(i))->value();
+ DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
+
+ Object* value = dictionary->ValueAt(index);
+ PropertyType type = dictionary->DetailsAt(index).type();
+ DCHECK(type != FIELD);
+ if (type == NORMAL && !value->IsJSFunction()) {
+ number_of_fields += 1;
}
}
// Fill in the instance descriptor and the fields.
int current_offset = 0;
- for (int i = 0; i < capacity; i++) {
- Object* k = dictionary->KeyAt(i);
- if (dictionary->IsKey(k)) {
- Object* value = dictionary->ValueAt(i);
- Handle<Name> key;
- if (k->IsSymbol()) {
- key = handle(Symbol::cast(k));
- } else {
- // Ensure the key is a unique name before writing into the
- // instance descriptor.
- key = factory->InternalizeString(handle(String::cast(k)));
- }
+ for (int i = 0; i < instance_descriptor_length; i++) {
+ int index = Smi::cast(iteration_order->get(i))->value();
+ Object* k = dictionary->KeyAt(index);
+ DCHECK(dictionary->IsKey(k));
- PropertyDetails details = dictionary->DetailsAt(i);
- int enumeration_index = details.dictionary_index();
- PropertyType type = details.type();
-
- if (value->IsJSFunction()) {
- ConstantDescriptor d(key,
- handle(value, isolate),
- details.attributes());
- descriptors->Set(enumeration_index - 1, &d);
- } else if (type == NORMAL) {
- if (current_offset < inobject_props) {
- object->InObjectPropertyAtPut(current_offset,
- value,
- UPDATE_WRITE_BARRIER);
- } else {
- int offset = current_offset - inobject_props;
- fields->set(offset, value);
- }
- FieldDescriptor d(key,
- current_offset++,
- details.attributes(),
- // TODO(verwaest): value->OptimalRepresentation();
- Representation::Tagged());
- descriptors->Set(enumeration_index - 1, &d);
- } else if (type == CALLBACKS) {
- CallbacksDescriptor d(key,
- handle(value, isolate),
- details.attributes());
- descriptors->Set(enumeration_index - 1, &d);
+ Object* value = dictionary->ValueAt(index);
+ Handle<Name> key;
+ if (k->IsSymbol()) {
+ key = handle(Symbol::cast(k));
+ } else {
+ // Ensure the key is a unique name before writing into the
+ // instance descriptor.
+ key = factory->InternalizeString(handle(String::cast(k)));
+ }
+
+ PropertyDetails details = dictionary->DetailsAt(index);
+ int enumeration_index = details.dictionary_index();
+ PropertyType type = details.type();
+
+ if (value->IsJSFunction()) {
+ ConstantDescriptor d(key, handle(value, isolate), details.attributes());
+ descriptors->Set(enumeration_index - 1, &d);
+ } else if (type == NORMAL) {
+ if (current_offset < inobject_props) {
+ object->InObjectPropertyAtPut(current_offset, value,
+ UPDATE_WRITE_BARRIER);
} else {
- UNREACHABLE();
+ int offset = current_offset - inobject_props;
+ fields->set(offset, value);
}
+ FieldDescriptor d(key, current_offset++, details.attributes(),
+ // TODO(verwaest): value->OptimalRepresentation();
+ Representation::Tagged());
+ descriptors->Set(enumeration_index - 1, &d);
+ } else if (type == CALLBACKS) {
+ CallbacksDescriptor d(key, handle(value, isolate), details.attributes());
+ descriptors->Set(enumeration_index - 1, &d);
+ } else {
+ UNREACHABLE();
}
}
DCHECK(current_offset == number_of_fields);
if (!maybe.has_value) return MaybeHandle<Object>();
if (!maybe.value) {
Handle<String> name = factory->Uint32ToString(index);
- EnqueueChangeRecord(object, "delete", name, old_value);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueChangeRecord(object, "delete", name, old_value),
+ Object);
}
}
ReoptimizeIfPrototype(holder);
if (is_observed) {
- EnqueueChangeRecord(object, "delete", name, old_value);
+ RETURN_ON_EXCEPTION(
+ it.isolate(),
+ EnqueueChangeRecord(object, "delete", name, old_value), Object);
}
return result;
DCHECK(!object->map()->is_extensible());
if (object->map()->is_observed()) {
- EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
- isolate->factory()->the_hole_value());
+ RETURN_ON_EXCEPTION(
+ isolate,
+ EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
+ isolate->factory()->the_hole_value()),
+ Object);
}
return object;
}
if (is_observed) {
const char* type = preexists ? "reconfigure" : "add";
- EnqueueChangeRecord(object, type, name, old_value);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueChangeRecord(object, type, name, old_value), Object);
}
return isolate->factory()->undefined_value();
if (old_size == 0) {
descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
} else {
- EnsureDescriptorSlack(map, old_size < 4 ? 1 : old_size / 2);
+ EnsureDescriptorSlack(
+ map, SlackForArraySize(old_size, kMaxNumberOfDescriptors));
descriptors = handle(map->instance_descriptors());
}
}
DCHECK(child->is_prototype_map());
} else {
Handle<TransitionArray> transitions =
- TransitionArray::CopyInsert(parent, name, child, flag);
- parent->set_transitions(*transitions);
+ TransitionArray::Insert(parent, name, child, flag);
+ if (!parent->HasTransitionArray() ||
+ *transitions != parent->transitions()) {
+ parent->set_transitions(*transitions);
+ }
child->SetBackPointer(*parent);
}
}
DCHECK(kind != map->elements_kind());
}
- bool insert_transition =
- flag == INSERT_TRANSITION && !map->HasElementsTransition();
+ bool insert_transition = flag == INSERT_TRANSITION &&
+ map->CanHaveMoreTransitions() &&
+ !map->HasElementsTransition();
if (insert_transition && map->owns_descriptors()) {
// In case the map owned its own descriptors, share the descriptors and
new_map->InitializeDescriptors(map->instance_descriptors());
}
- Handle<Name> name = isolate->factory()->observed_symbol();
- ConnectTransition(map, new_map, name, FULL_TRANSITION);
-
+ if (map->CanHaveMoreTransitions()) {
+ Handle<Name> name = isolate->factory()->observed_symbol();
+ ConnectTransition(map, new_map, name, FULL_TRANSITION);
+ }
return new_map;
}
int value = Smi::cast(*IteratorField())->value();
int index = -value - 1;
int number_of_transitions = transition_array_->number_of_transitions();
- while (index < number_of_transitions) {
+ if (index < number_of_transitions) {
*IteratorField() = Smi::FromInt(value - 1);
return transition_array_->GetTarget(index);
}
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
return SmartArrayPointer<char>(NULL);
}
- Heap* heap = GetHeap();
-
// Negative length means the to the end of the string.
if (length < 0) length = kMaxInt - offset;
// Compute the size of the UTF-8 string. Start at the specified offset.
- Access<ConsStringIteratorOp> op(
- heap->isolate()->objects_string_iterator());
- StringCharacterStream stream(this, op.value(), offset);
+ StringCharacterStream stream(this, offset);
int character_position = offset;
int utf8_bytes = 0;
int last = unibrow::Utf16::kNoPreviousCharacter;
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
return SmartArrayPointer<uc16>();
}
- Heap* heap = GetHeap();
-
- Access<ConsStringIteratorOp> op(
- heap->isolate()->objects_string_iterator());
- StringCharacterStream stream(this, op.value());
+ StringCharacterStream stream(this);
uc16* result = NewArray<uc16>(length() + 1);
}
-void ConsStringIteratorOp::Initialize(ConsString* cons_string, int offset) {
+void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
DCHECK(cons_string != NULL);
root_ = cons_string;
consumed_ = offset;
}
-String* ConsStringIteratorOp::Continue(int* offset_out) {
+String* ConsStringIterator::Continue(int* offset_out) {
DCHECK(depth_ != 0);
DCHECK_EQ(0, *offset_out);
bool blew_stack = StackBlown();
}
-String* ConsStringIteratorOp::Search(int* offset_out) {
+String* ConsStringIterator::Search(int* offset_out) {
ConsString* cons_string = root_;
// Reset the stack, pushing the root string.
depth_ = 1;
}
-String* ConsStringIteratorOp::NextLeaf(bool* blew_stack) {
+String* ConsStringIterator::NextLeaf(bool* blew_stack) {
while (true) {
// Tree traversal complete.
if (depth_ == 0) {
class StringComparator {
class State {
public:
- explicit inline State(ConsStringIteratorOp* op)
- : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {}
+ State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
- inline void Init(String* string) {
+ void Init(String* string) {
ConsString* cons_string = String::VisitFlat(this, string);
- op_->Reset(cons_string);
+ iter_.Reset(cons_string);
if (cons_string != NULL) {
int offset;
- string = op_->Next(&offset);
+ string = iter_.Next(&offset);
String::VisitFlat(this, string, offset);
}
}
}
// Advance state.
int offset;
- String* next = op_->Next(&offset);
+ String* next = iter_.Next(&offset);
DCHECK_EQ(0, offset);
DCHECK(next != NULL);
String::VisitFlat(this, next);
}
- ConsStringIteratorOp* const op_;
+ ConsStringIterator iter_;
bool is_one_byte_;
int length_;
union {
};
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(State);
+ DISALLOW_COPY_AND_ASSIGN(State);
};
public:
- inline StringComparator(ConsStringIteratorOp* op_1,
- ConsStringIteratorOp* op_2)
- : state_1_(op_1),
- state_2_(op_2) {
- }
+ inline StringComparator() {}
template<typename Chars1, typename Chars2>
static inline bool Equals(State* state_1, State* state_2, int to_check) {
private:
State state_1_;
State state_2_;
- DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator);
+
+ DISALLOW_COPY_AND_ASSIGN(StringComparator);
};
return CompareRawStringContents(str1, str2, len);
}
- Isolate* isolate = GetIsolate();
- StringComparator comparator(isolate->objects_string_compare_iterator_a(),
- isolate->objects_string_compare_iterator_b());
-
+ StringComparator comparator;
return comparator.Equals(this, other);
}
bool String::ComputeArrayIndex(uint32_t* index) {
int length = this->length();
if (length == 0 || length > kMaxArrayIndexSize) return false;
- ConsStringIteratorOp op;
- StringCharacterStream stream(this, &op);
+ StringCharacterStream stream(this);
return StringToArrayIndex(&stream, index);
}
}
+inline static uint32_t ObjectAddressForHashing(Object* object) {
+ uint32_t value = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object));
+ return value & MemoryChunk::kAlignmentMask;
+}
+
+
int Map::Hash() {
// For performance reasons we only hash the 3 most variable fields of a map:
- // constructor, prototype and bit_field2.
+ // constructor, prototype and bit_field2. For predictability reasons we
+ // use objects' offsets in respective pages for hashing instead of raw
+ // addresses.
// Shift away the tag.
- int hash = (static_cast<uint32_t>(
- reinterpret_cast<uintptr_t>(constructor())) >> 2);
+ int hash = ObjectAddressForHashing(constructor()) >> 2;
// XOR-ing the prototype and constructor directly yields too many zero bits
// when the two pointers are close (which is fairly common).
- // To avoid this we shift the prototype 4 bits relatively to the constructor.
- hash ^= (static_cast<uint32_t>(
- reinterpret_cast<uintptr_t>(prototype())) << 2);
+ // To avoid this we shift the prototype bits relatively to the constructor.
+ hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
return hash ^ (hash >> 16) ^ bit_field2();
}
}
-// Wrappers for scripts are kept alive and cached in weak global
-// handles referred from foreign objects held by the scripts as long as
-// they are used. When they are not used anymore, the garbage
-// collector will call the weak callback on the global handle
-// associated with the wrapper and get rid of both the wrapper and the
-// handle.
-static void ClearWrapperCacheWeakCallback(
- const v8::WeakCallbackData<v8::Value, void>& data) {
- Object** location = reinterpret_cast<Object**>(data.GetParameter());
- JSValue* wrapper = JSValue::cast(*location);
- Script::cast(wrapper->value())->ClearWrapperCache();
-}
-
-
-void Script::ClearWrapperCache() {
- Foreign* foreign = wrapper();
- Object** location = reinterpret_cast<Object**>(foreign->foreign_address());
- DCHECK_EQ(foreign->foreign_address(), reinterpret_cast<Address>(location));
- foreign->set_foreign_address(0);
- GlobalHandles::Destroy(location);
- GetIsolate()->counters()->script_wrappers()->Decrement();
-}
-
-
Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
- if (script->wrapper()->foreign_address() != NULL) {
- // Return a handle for the existing script wrapper from the cache.
- return Handle<JSValue>(
- *reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
- }
Isolate* isolate = script->GetIsolate();
+ if (!script->wrapper()->IsUndefined()) {
+ Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
+ if (!cell->cleared()) {
+ // Return a handle for the existing script wrapper from the cache.
+ return handle(JSObject::cast(cell->value()));
+ }
+ // If we found an empty WeakCell, that means the script wrapper was
+ // GCed. We are not notified directly of that, so we decrement here
+ // so that we at least don't count double for any given script.
+ isolate->counters()->script_wrappers()->Decrement();
+ }
// Construct a new script wrapper.
isolate->counters()->script_wrappers()->Increment();
Handle<JSFunction> constructor = isolate->script_function();
Handle<JSValue> result =
Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
-
result->set_value(*script);
-
- // Create a new weak global handle and use it to cache the wrapper
- // for future use. The cache will automatically be cleared by the
- // garbage collector when it is not used anymore.
- Handle<Object> handle = isolate->global_handles()->Create(*result);
- GlobalHandles::MakeWeak(handle.location(),
- reinterpret_cast<void*>(handle.location()),
- &ClearWrapperCacheWeakCallback);
- script->wrapper()->set_foreign_address(
- reinterpret_cast<Address>(handle.location()));
+ Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
+ script->set_wrapper(*cell);
return result;
}
// Output the source code without any allocation in the heap.
-OStream& operator<<(OStream& os, const SourceCodeOf& v) {
+std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
const SharedFunctionInfo* s = v.value;
// For some native functions there is no source.
if (!s->HasSourceCode()) return os << "<No Source>";
void SharedFunctionInfo::ClearTypeFeedbackInfo() {
- TypeFeedbackVector* vector = feedback_vector();
- Heap* heap = GetHeap();
- int length = vector->length();
-
- for (int i = 0; i < length; i++) {
- Object* obj = vector->get(i);
- if (obj->IsHeapObject()) {
- InstanceType instance_type =
- HeapObject::cast(obj)->map()->instance_type();
- switch (instance_type) {
- case ALLOCATION_SITE_TYPE:
- // AllocationSites are not cleared because they do not store
- // information that leaks.
- break;
- // Fall through...
- default:
- vector->set(i, TypeFeedbackVector::RawUninitializedSentinel(heap),
- SKIP_WRITE_BARRIER);
- }
- }
- }
+ feedback_vector()->ClearSlots(this);
}
}
+void Code::MakeYoung() {
+ byte* sequence = FindCodeAgeSequence();
+ if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, GetIsolate());
+}
+
+
void Code::MakeOlder(MarkingParity current_parity) {
byte* sequence = FindCodeAgeSequence();
if (sequence != NULL) {
#ifdef ENABLE_DISASSEMBLER
void DeoptimizationInputData::DeoptimizationInputDataPrint(
- OStream& os) { // NOLINT
+ std::ostream& os) { // NOLINT
disasm::NameConverter converter;
int deopt_count = DeoptCount();
os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
break;
}
- case Translation::FLOAT32x4_REGISTER: {
- int reg_code = iterator.Next();
- os << "{input=" << SIMD128Register::AllocationIndexToString(reg_code)
- << "}";
- break;
- }
-
- case Translation::FLOAT64x2_REGISTER: {
- int reg_code = iterator.Next();
- os << "{input=" << SIMD128Register::AllocationIndexToString(reg_code)
- << "}";
- break;
- }
-
- case Translation::INT32x4_REGISTER: {
- int reg_code = iterator.Next();
- os << "{input=" << SIMD128Register::AllocationIndexToString(reg_code)
- << "}";
- break;
- }
-
case Translation::STACK_SLOT: {
int input_slot_index = iterator.Next();
os << "{input=" << input_slot_index << "}";
break;
}
- case Translation::FLOAT32x4_STACK_SLOT: {
- int input_slot_index = iterator.Next();
- os << "{input=" << input_slot_index << "}";
- break;
- }
-
- case Translation::FLOAT64x2_STACK_SLOT: {
- int input_slot_index = iterator.Next();
- os << "{input=" << input_slot_index << "}";
- break;
- }
-
- case Translation::INT32x4_STACK_SLOT: {
- int input_slot_index = iterator.Next();
- os << "{input=" << input_slot_index << "}";
- break;
- }
-
case Translation::LITERAL: {
unsigned literal_index = iterator.Next();
os << "{literal_id=" << literal_index << "}";
void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
- OStream& os) { // NOLINT
+ std::ostream& os) { // NOLINT
os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
<< ")\n";
if (this->DeoptPoints() == 0) return;
}
-void Code::PrintExtraICState(OStream& os, // NOLINT
+void Code::PrintExtraICState(std::ostream& os, // NOLINT
Kind kind, ExtraICState extra) {
os << "extra_ic_state = ";
if ((kind == STORE_IC || kind == KEYED_STORE_IC) && (extra == STRICT)) {
}
-void Code::Disassemble(const char* name, OStream& os) { // NOLINT
+void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
os << "kind = " << Kind2String(kind()) << "\n";
if (IsCodeStubOrIC()) {
const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this), true);
}
os << "Instructions (size = " << instruction_size() << ")\n";
- // TODO(svenpanne) The Disassembler should use streams, too!
{
- CodeTracer::Scope trace_scope(GetIsolate()->GetCodeTracer());
- Disassembler::Decode(trace_scope.file(), this);
+ Isolate* isolate = GetIsolate();
+ int decode_size = is_crankshafted()
+ ? static_cast<int>(safepoint_table_offset())
+ : instruction_size();
+ // If there might be a back edge table, stop before reaching it.
+ if (kind() == Code::FUNCTION) {
+ decode_size =
+ Min(decode_size, static_cast<int>(back_edge_table_offset()));
+ }
+ byte* begin = instruction_start();
+ byte* end = begin + decode_size;
+ Disassembler::Decode(isolate, &os, begin, end, this);
}
os << "\n";
os << "Safepoints (size = " << table.size() << ")\n";
for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i);
- os << (instruction_start() + pc_offset) << " ";
+ os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
// TODO(svenpanne) Add some basic formatting to our streams.
Vector<char> buf1 = Vector<char>::New(30);
SNPrintF(buf1, "%4d", pc_offset);
it.rinfo()->Print(GetIsolate(), os);
}
os << "\n";
+
+#ifdef OBJECT_PRINT
+ if (FLAG_enable_ool_constant_pool) {
+ ConstantPoolArray* pool = constant_pool();
+ if (pool->length()) {
+ os << "Constant Pool\n";
+ pool->Print(os);
+ os << "\n";
+ }
+ }
+#endif
}
#endif // ENABLE_DISASSEMBLER
return true;
}
-static void EnqueueSpliceRecord(Handle<JSArray> object,
- uint32_t index,
- Handle<JSArray> deleted,
- uint32_t add_count) {
+MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord(
+ Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted,
+ uint32_t add_count) {
Isolate* isolate = object->GetIsolate();
HandleScope scope(isolate);
Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
Handle<Object> args[] =
{ object, index_object, deleted, add_count_object };
- Execution::Call(isolate,
- Handle<JSFunction>(isolate->observers_enqueue_splice()),
- isolate->factory()->undefined_value(),
- arraysize(args),
- args).Assert();
+ return Execution::Call(
+ isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()),
+ isolate->factory()->undefined_value(), arraysize(args), args);
}
-static void BeginPerformSplice(Handle<JSArray> object) {
+MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice(
+ Handle<JSArray> object) {
Isolate* isolate = object->GetIsolate();
HandleScope scope(isolate);
Handle<Object> args[] = { object };
- Execution::Call(isolate,
- Handle<JSFunction>(isolate->observers_begin_perform_splice()),
- isolate->factory()->undefined_value(),
- arraysize(args),
- args).Assert();
+ return Execution::Call(
+ isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()),
+ isolate->factory()->undefined_value(), arraysize(args), args);
}
-static void EndPerformSplice(Handle<JSArray> object) {
+MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice(
+ Handle<JSArray> object) {
Isolate* isolate = object->GetIsolate();
HandleScope scope(isolate);
Handle<Object> args[] = { object };
- Execution::Call(isolate,
- Handle<JSFunction>(isolate->observers_end_perform_splice()),
- isolate->factory()->undefined_value(),
- arraysize(args),
- args).Assert();
+ return Execution::Call(
+ isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()),
+ isolate->factory()->undefined_value(), arraysize(args), args);
}
CHECK(array->length()->ToArrayIndex(&new_length));
if (old_length == new_length) return hresult;
- BeginPerformSplice(array);
+ RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
for (int i = 0; i < indices.length(); ++i) {
// For deletions where the property was an accessor, old_values[i]
// will be the hole, which instructs EnqueueChangeRecord to elide
// the "oldValue" property.
- JSObject::EnqueueChangeRecord(
- array, "delete", isolate->factory()->Uint32ToString(indices[i]),
- old_values[i]);
+ RETURN_ON_EXCEPTION(
+ isolate,
+ JSObject::EnqueueChangeRecord(
+ array, "delete", isolate->factory()->Uint32ToString(indices[i]),
+ old_values[i]),
+ Object);
}
- JSObject::EnqueueChangeRecord(
- array, "update", isolate->factory()->length_string(),
- old_length_handle);
+ RETURN_ON_EXCEPTION(isolate,
+ JSObject::EnqueueChangeRecord(
+ array, "update", isolate->factory()->length_string(),
+ old_length_handle),
+ Object);
- EndPerformSplice(array);
+ RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
uint32_t index = Min(old_length, new_length);
uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
STRICT).Assert();
}
- EnqueueSpliceRecord(array, index, deleted, add_count);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object);
return hresult;
}
DCHECK(new_map->prototype() == *value);
JSObject::MigrateToMap(real_receiver, new_map);
- if (!dictionary_elements_in_chain &&
+ if (from_javascript && !dictionary_elements_in_chain &&
new_map->DictionaryElementsInPrototypeChainOnly()) {
// If the prototype chain didn't previously have element callbacks, then
// KeyedStoreICs need to be cleared to ensure any that involve this
}
-MaybeHandle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object,
- Handle<Object> structure,
- uint32_t index,
- Handle<Object> value,
- Handle<JSObject> holder,
- StrictMode strict_mode) {
- Isolate* isolate = object->GetIsolate();
+MaybeHandle<Object> JSObject::SetElementWithCallback(
+ Handle<Object> object, Handle<Object> structure, uint32_t index,
+ Handle<Object> value, Handle<JSObject> holder, StrictMode strict_mode) {
+ Isolate* isolate = holder->GetIsolate();
// We should never get here to initialize a const with the hole
// value since a const declaration would conflict with the setter.
if (call_fun == NULL) return value;
Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Handle<String> key(isolate->factory()->NumberToString(number));
- LOG(isolate, ApiNamedPropertyAccess("store", *object, *key));
+ LOG(isolate, ApiNamedPropertyAccess("store", *holder, *key));
PropertyCallbackArguments
args(isolate, data->data(), *object, *holder);
args.Call(call_fun,
if (object->HasExternalArrayElements() ||
object->HasFixedTypedArrayElements()) {
- if (!value->IsNumber() && !value->IsFloat32x4() && !value->IsFloat64x2() &&
- !value->IsInt32x4() && !value->IsUndefined()) {
+ if (!value->IsNumber() && !value->IsUndefined()) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value,
Execution::ToNumber(isolate, value), Object);
CHECK(old_length_handle->ToArrayIndex(&old_length));
CHECK(new_length_handle->ToArrayIndex(&new_length));
- BeginPerformSplice(Handle<JSArray>::cast(object));
- EnqueueChangeRecord(object, "add", name, old_value);
- EnqueueChangeRecord(object, "update", isolate->factory()->length_string(),
- old_length_handle);
- EndPerformSplice(Handle<JSArray>::cast(object));
+ RETURN_ON_EXCEPTION(
+ isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueChangeRecord(object, "add", name, old_value), Object);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueChangeRecord(object, "update",
+ isolate->factory()->length_string(),
+ old_length_handle),
+ Object);
+ RETURN_ON_EXCEPTION(
+ isolate, EndPerformSplice(Handle<JSArray>::cast(object)), Object);
Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
- EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, deleted,
- new_length - old_length);
+ RETURN_ON_EXCEPTION(
+ isolate,
+ EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length,
+ deleted, new_length - old_length),
+ Object);
} else {
- EnqueueChangeRecord(object, "add", name, old_value);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueChangeRecord(object, "add", name, old_value), Object);
}
} else if (old_value->IsTheHole()) {
- EnqueueChangeRecord(object, "reconfigure", name, old_value);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value),
+ Object);
} else {
Handle<Object> new_value =
Object::GetElement(isolate, object, index).ToHandleChecked();
bool value_changed = !old_value->SameValue(*new_value);
if (old_attributes != new_attributes) {
if (!value_changed) old_value = isolate->factory()->the_hole_value();
- EnqueueChangeRecord(object, "reconfigure", name, old_value);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value),
+ Object);
} else if (value_changed) {
- EnqueueChangeRecord(object, "update", name, old_value);
+ RETURN_ON_EXCEPTION(
+ isolate, EnqueueChangeRecord(object, "update", name, old_value),
+ Object);
}
}
// we keep it here instead to satisfy certain compilers.
#ifdef OBJECT_PRINT
template <typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::Print(OStream& os) { // NOLINT
+void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
int capacity = DerivedHashTable::Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = DerivedHashTable::KeyAt(i);
} else {
os << Brief(k);
}
- os << ": " << Brief(ValueAt(i)) << "\n";
+ os << ": " << Brief(ValueAt(i)) << " " << DetailsAt(i) << "\n";
}
}
}
}
+const char* Symbol::PrivateSymbolToName() const {
+ Heap* heap = GetIsolate()->heap();
+#define SYMBOL_CHECK_AND_PRINT(name) \
+ if (this == heap->name()) return #name;
+ PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
+#undef SYMBOL_CHECK_AND_PRINT
+ return "UNKNOWN";
+}
+
+
+void Symbol::SymbolShortPrint(std::ostream& os) {
+ os << "<Symbol: " << Hash();
+ if (!name()->IsUndefined()) {
+ os << " ";
+ HeapStringAllocator allocator;
+ StringStream accumulator(&allocator);
+ String::cast(name())->StringShortPrint(&accumulator);
+ os << accumulator.ToCString().get();
+ } else {
+ os << " (" << PrivateSymbolToName() << ")";
+ }
+ os << ">";
+}
+
+
// StringSharedKeys are used as keys in the eval cache.
class StringSharedKey : public HashTableKey {
public:
bool IsMatch(Object* other) OVERRIDE {
DisallowHeapAllocation no_allocation;
- if (!other->IsFixedArray()) return false;
+ if (!other->IsFixedArray()) {
+ if (!other->IsNumber()) return false;
+ uint32_t other_hash = static_cast<uint32_t>(other->Number());
+ return Hash() == other_hash;
+ }
FixedArray* other_array = FixedArray::cast(other);
SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
if (shared != *shared_) return false;
uint32_t HashForObject(Object* obj) OVERRIDE {
DisallowHeapAllocation no_allocation;
+ if (obj->IsNumber()) {
+ return static_cast<uint32_t>(obj->Number());
+ }
FixedArray* other_array = FixedArray::cast(obj);
SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
String* source = String::cast(other_array->get(1));
Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
-template void
-Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
- GenerateNewEnumerationIndices(Handle<NameDictionary>);
+template Handle<FixedArray> Dictionary<
+ NameDictionary, NameDictionaryShape,
+ Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
+
+template Handle<FixedArray> Dictionary<
+ NameDictionary, NameDictionaryShape,
+ Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
template int
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
NumberOfEnumElements();
-template
-int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
- FindEntry(uint32_t);
+template bool Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
+ uint32_t>::HasComplexElements();
+
+template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
+ uint32_t>::FindEntry(uint32_t);
Handle<Object> JSObject::PrepareSlowElementsForSort(
}
-Handle<Object> ExternalFloat32x4Array::SetValue(
- Handle<ExternalFloat32x4Array> array,
- uint32_t index,
- Handle<Object> value) {
- float32x4_value_t cast_value;
- cast_value.storage[0] = static_cast<float>(base::OS::nan_value());
- cast_value.storage[1] = static_cast<float>(base::OS::nan_value());
- cast_value.storage[2] = static_cast<float>(base::OS::nan_value());
- cast_value.storage[3] = static_cast<float>(base::OS::nan_value());
- if (index < static_cast<uint32_t>(array->length())) {
- if (value->IsFloat32x4()) {
- cast_value = Handle<Float32x4>::cast(value)->get();
- } 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());
- }
- array->set(index, cast_value);
- }
- return array->GetIsolate()->factory()->NewFloat32x4(cast_value);
-}
-
-
-Handle<Object> ExternalInt32x4Array::SetValue(
- Handle<ExternalInt32x4Array> array, uint32_t index, Handle<Object> value) {
- int32x4_value_t cast_value;
- cast_value.storage[0] = 0;
- cast_value.storage[1] = 0;
- cast_value.storage[2] = 0;
- cast_value.storage[3] = 0;
- if (index < static_cast<uint32_t>(array->length())) {
- if (value->IsInt32x4()) {
- cast_value = Handle<Int32x4>::cast(value)->get();
- } 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());
- }
- array->set(index, cast_value);
- }
- return array->GetIsolate()->factory()->NewInt32x4(cast_value);
-}
-
-
-Handle<Object> ExternalFloat64x2Array::SetValue(
- Handle<ExternalFloat64x2Array> array,
- uint32_t index,
- Handle<Object> value) {
- float64x2_value_t cast_value;
- cast_value.storage[0] = base::OS::nan_value();
- cast_value.storage[1] = base::OS::nan_value();
- if (index < static_cast<uint32_t>(array->length())) {
- if (value->IsFloat64x2()) {
- cast_value = Handle<Float64x2>::cast(value)->get();
- } 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());
- }
- array->set(index, cast_value);
- }
- return array->GetIsolate()->factory()->NewFloat64x2(cast_value);
-}
-
-
Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
Handle<JSGlobalObject> global,
Handle<Name> name) {
}
+void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
+ int expected) {
+ Handle<StringTable> table = isolate->factory()->string_table();
+ // We need a key instance for the virtual hash function.
+ InternalizedStringKey dummy_key(Handle<String>::null());
+ table = StringTable::EnsureCapacity(table, expected, &dummy_key);
+ isolate->factory()->set_string_table(table);
+}
+
+
Handle<String> StringTable::LookupString(Isolate* isolate,
Handle<String> string) {
InternalizedStringKey key(string);
RelocInfo::kNoPosition);
int entry = FindEntry(&key);
if (entry == kNotFound) return isolate->factory()->undefined_value();
- return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
+ int index = EntryToIndex(entry);
+ if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
+ return Handle<Object>(get(index + 1), isolate);
}
StringSharedKey key(src, outer_info, strict_mode, scope_position);
int entry = FindEntry(&key);
if (entry == kNotFound) return isolate->factory()->undefined_value();
+ int index = EntryToIndex(entry);
+ if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
}
Handle<SharedFunctionInfo> shared(context->closure()->shared());
StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
RelocInfo::kNoPosition);
+ int entry = cache->FindEntry(&key);
+ if (entry != kNotFound) {
+ Handle<Object> k = key.AsHandle(isolate);
+ cache->set(EntryToIndex(entry), *k);
+ cache->set(EntryToIndex(entry) + 1, *value);
+ return cache;
+ }
+
cache = EnsureCapacity(cache, 1, &key);
- Handle<Object> k = key.AsHandle(isolate);
- int entry = cache->FindInsertionEntry(key.Hash());
+ entry = cache->FindInsertionEntry(key.Hash());
+ Handle<Object> k =
+ isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
cache->set(EntryToIndex(entry), *k);
- cache->set(EntryToIndex(entry) + 1, *value);
+ cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
cache->ElementAdded();
return cache;
}
int scope_position) {
Isolate* isolate = cache->GetIsolate();
StringSharedKey key(src, outer_info, value->strict_mode(), scope_position);
+ int entry = cache->FindEntry(&key);
+ if (entry != kNotFound) {
+ Handle<Object> k = key.AsHandle(isolate);
+ cache->set(EntryToIndex(entry), *k);
+ cache->set(EntryToIndex(entry) + 1, *value);
+ return cache;
+ }
+
cache = EnsureCapacity(cache, 1, &key);
- Handle<Object> k = key.AsHandle(isolate);
- int entry = cache->FindInsertionEntry(key.Hash());
+ entry = cache->FindInsertionEntry(key.Hash());
+ Handle<Object> k =
+ isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
cache->set(EntryToIndex(entry), *k);
- cache->set(EntryToIndex(entry) + 1, *value);
+ cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
cache->ElementAdded();
return cache;
}
}
+void CompilationCacheTable::Age() {
+ DisallowHeapAllocation no_allocation;
+ Object* the_hole_value = GetHeap()->the_hole_value();
+ for (int entry = 0, size = Capacity(); entry < size; entry++) {
+ int entry_index = EntryToIndex(entry);
+ int value_index = entry_index + 1;
+
+ if (get(entry_index)->IsNumber()) {
+ Smi* count = Smi::cast(get(value_index));
+ count = Smi::FromInt(count->value() - 1);
+ if (count->value() == 0) {
+ NoWriteBarrierSet(this, entry_index, the_hole_value);
+ NoWriteBarrierSet(this, value_index, the_hole_value);
+ ElementRemoved();
+ } else {
+ NoWriteBarrierSet(this, value_index, count);
+ }
+ } else if (get(entry_index)->IsFixedArray()) {
+ SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
+ if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
+ NoWriteBarrierSet(this, entry_index, the_hole_value);
+ NoWriteBarrierSet(this, value_index, the_hole_value);
+ ElementRemoved();
+ }
+ }
+ }
+}
+
+
void CompilationCacheTable::Remove(Object* value) {
DisallowHeapAllocation no_allocation;
Object* the_hole_value = GetHeap()->the_hole_value();
}
-template<typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
+template <typename Derived, typename Shape, typename Key>
+Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
Handle<Derived> dictionary) {
Factory* factory = dictionary->GetIsolate()->factory();
int length = dictionary->NumberOfElements();
- // Allocate and initialize iteration order array.
Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
- for (int i = 0; i < length; i++) {
- iteration_order->set(i, Smi::FromInt(i));
- }
-
- // Allocate array with enumeration order.
Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
- // Fill the enumeration order array with property details.
+ // Fill both the iteration order array and the enumeration order array
+ // with property details.
int capacity = dictionary->Capacity();
int pos = 0;
for (int i = 0; i < capacity; i++) {
if (dictionary->IsKey(dictionary->KeyAt(i))) {
int index = dictionary->DetailsAt(i).dictionary_index();
- enumeration_order->set(pos++, Smi::FromInt(index));
+ iteration_order->set(pos, Smi::FromInt(i));
+ enumeration_order->set(pos, Smi::FromInt(index));
+ pos++;
}
}
+ DCHECK(pos == length);
// Sort the arrays wrt. enumeration order.
iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
+ return iteration_order;
+}
+
+
+template <typename Derived, typename Shape, typename Key>
+Handle<FixedArray>
+Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
+ Handle<Derived> dictionary) {
+ int length = dictionary->NumberOfElements();
+
+ Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
+ DCHECK(iteration_order->length() == length);
- // Overwrite the enumeration_order with the enumeration indices.
+ // Iterate over the dictionary using the enumeration order and update
+ // the dictionary with new enumeration indices.
for (int i = 0; i < length; i++) {
int index = Smi::cast(iteration_order->get(i))->value();
+ DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
+
int enum_index = PropertyDetails::kInitialIndex + i;
- enumeration_order->set(index, Smi::FromInt(enum_index));
- }
- // Update the dictionary with new indices.
- capacity = dictionary->Capacity();
- pos = 0;
- for (int i = 0; i < capacity; i++) {
- if (dictionary->IsKey(dictionary->KeyAt(i))) {
- int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
- PropertyDetails details = dictionary->DetailsAt(i);
- PropertyDetails new_details = PropertyDetails(
- details.attributes(), details.type(), enum_index);
- dictionary->DetailsAtPut(i, new_details);
- }
+ PropertyDetails details = dictionary->DetailsAt(index);
+ PropertyDetails new_details =
+ PropertyDetails(details.attributes(), details.type(), enum_index);
+ dictionary->DetailsAtPut(index, new_details);
}
// Set the next enumeration index.
dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
+ return iteration_order;
}
}
-template<typename Derived, typename Shape, typename Key>
+template <typename Derived, typename Shape, typename Key>
+bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
+ int capacity = DerivedHashTable::Capacity();
+ for (int i = 0; i < capacity; i++) {
+ Object* k = DerivedHashTable::KeyAt(i);
+ if (DerivedHashTable::IsKey(k) && !FilterKey(k, NONE)) {
+ PropertyDetails details = DetailsAt(i);
+ if (details.IsDeleted()) continue;
+ if (details.type() == CALLBACKS) return true;
+ PropertyAttributes attr = details.attributes();
+ if (attr & (READ_ONLY | DONT_DELETE | DONT_ENUM)) return true;
+ }
+ }
+ return false;
+}
+
+
+template <typename Derived, typename Shape, typename Key>
void Dictionary<Derived, Shape, Key>::CopyKeysTo(
- FixedArray* storage,
- PropertyAttributes filter,
+ FixedArray* storage, PropertyAttributes filter,
typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
int capacity = DerivedHashTable::Capacity();
void JSArrayBuffer::Neuter() {
- DCHECK(is_external());
+ CHECK(is_neuterable());
+ CHECK(is_external());
set_backing_store(NULL);
set_byte_length(Smi::FromInt(0));
}
void JSArrayBufferView::NeuterView() {
+ CHECK(JSArrayBuffer::cast(buffer())->is_neuterable());
set_byte_offset(Smi::FromInt(0));
set_byte_length(Smi::FromInt(0));
}