vendor/v8/src/runtime.cc in libv8-3.10.8.0 vs vendor/v8/src/runtime.cc in libv8-3.11.8.0
- old
+ new
@@ -206,12 +206,14 @@
// Deep copy local elements.
// Pixel elements cannot be created using an object literal.
ASSERT(!copy->HasExternalArrayElements());
switch (copy->GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
+ case FAST_SMI_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
FixedArray* elements = FixedArray::cast(copy->elements());
if (elements->map() == heap->fixed_cow_array_map()) {
isolate->counters()->cow_arrays_created_runtime()->Increment();
#ifdef DEBUG
for (int i = 0; i < elements->length(); i++) {
@@ -221,11 +223,11 @@
} else {
for (int i = 0; i < elements->length(); i++) {
Object* value = elements->get(i);
ASSERT(value->IsSmi() ||
value->IsTheHole() ||
- (copy->GetElementsKind() == FAST_ELEMENTS));
+ (IsFastObjectElementsKind(copy->GetElementsKind())));
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
{ MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
js_object);
if (!maybe_result->ToObject(&result)) return maybe_result;
@@ -266,10 +268,11 @@
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
// No contained objects, nothing to do.
break;
}
return copy;
}
@@ -450,11 +453,11 @@
}
return isolate->ThrowIllegalOperation();
}
-static const int kSmiOnlyLiteralMinimumLength = 1024;
+static const int kSmiLiteralMinimumLength = 1024;
Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
Isolate* isolate,
Handle<FixedArray> literals,
@@ -468,27 +471,26 @@
ElementsKind constant_elements_kind =
static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(elements->get(1)));
+ ASSERT(IsFastElementsKind(constant_elements_kind));
Context* global_context = isolate->context()->global_context();
- if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
- object->set_map(Map::cast(global_context->smi_js_array_map()));
- } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
- object->set_map(Map::cast(global_context->double_js_array_map()));
- } else {
- object->set_map(Map::cast(global_context->object_js_array_map()));
- }
+ Object* maybe_maps_array = global_context->js_array_maps();
+ ASSERT(!maybe_maps_array->IsUndefined());
+ Object* maybe_map = FixedArray::cast(maybe_maps_array)->get(
+ constant_elements_kind);
+ ASSERT(maybe_map->IsMap());
+ object->set_map(Map::cast(maybe_map));
Handle<FixedArrayBase> copied_elements_values;
- if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
+ if (IsFastDoubleElementsKind(constant_elements_kind)) {
ASSERT(FLAG_smi_only_arrays);
copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
Handle<FixedDoubleArray>::cast(constant_elements_values));
} else {
- ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
- constant_elements_kind == FAST_ELEMENTS);
+ ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind));
const bool is_cow =
(constant_elements_values->map() ==
isolate->heap()->fixed_cow_array_map());
if (is_cow) {
copied_elements_values = constant_elements_values;
@@ -520,19 +522,26 @@
}
}
object->set_elements(*copied_elements_values);
object->set_length(Smi::FromInt(copied_elements_values->length()));
- // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
+ // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is
// on or the object is larger than the threshold.
if (!FLAG_smi_only_arrays &&
- constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
- if (object->GetElementsKind() != FAST_ELEMENTS) {
- CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
+ constant_elements_values->length() < kSmiLiteralMinimumLength) {
+ ElementsKind elements_kind = object->GetElementsKind();
+ if (!IsFastObjectElementsKind(elements_kind)) {
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS,
+ isolate)->IsFailure());
+ } else {
+ CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
+ }
}
}
+ object->ValidateElements();
return object;
}
static Handle<Object> CreateLiteralBoilerplate(
@@ -1728,11 +1737,11 @@
CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
// Due to the way the JS calls are constructed this must be less than the
// length of a string, i.e. it is always a Smi. We check anyway for security.
CONVERT_SMI_ARG_CHECKED(index, 2);
CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
- RUNTIME_ASSERT(last_match_info->HasFastElements());
+ RUNTIME_ASSERT(last_match_info->HasFastObjectElements());
RUNTIME_ASSERT(index >= 0);
RUNTIME_ASSERT(index <= subject->length());
isolate->counters()->regexp_entry_runtime()->Increment();
Handle<Object> result = RegExpImpl::Exec(regexp,
subject,
@@ -3102,11 +3111,11 @@
// string and possibly suffix after last match. It is possible for
// all components to use two elements when encoded as two smis.
const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
bool matched = true;
do {
- ASSERT(last_match_info_handle->HasFastElements());
+ ASSERT(last_match_info_handle->HasFastObjectElements());
// Increase the capacity of the builder before entering local handle-scope,
// so its internal buffer can safely allocate a new handle if it grows.
builder.EnsureCapacity(parts_added_per_loop);
HandleScope loop_scope(isolate);
@@ -3199,11 +3208,11 @@
0,
last_match_info_handle);
if (match.is_null()) return Failure::Exception();
if (match->IsNull()) return *subject_handle;
- ASSERT(last_match_info_handle->HasFastElements());
+ ASSERT(last_match_info_handle->HasFastObjectElements());
int start, end;
{
AssertNoAllocation match_info_array_is_not_in_a_handle;
FixedArray* match_info_array =
@@ -3273,11 +3282,11 @@
next,
last_match_info_handle);
if (match.is_null()) return Failure::Exception();
if (match->IsNull()) break;
- ASSERT(last_match_info_handle->HasFastElements());
+ ASSERT(last_match_info_handle->HasFastObjectElements());
HandleScope loop_scope(isolate);
{
AssertNoAllocation match_info_array_is_not_in_a_handle;
FixedArray* match_info_array =
FixedArray::cast(last_match_info_handle->elements());
@@ -3343,11 +3352,11 @@
}
CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
- ASSERT(last_match_info->HasFastElements());
+ ASSERT(last_match_info->HasFastObjectElements());
if (replacement->length() == 0) {
if (subject->HasOnlyAsciiChars()) {
return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
isolate, subject, regexp, last_match_info);
@@ -3793,66 +3802,77 @@
}
return false; // No matches at all.
}
-static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
+static int SearchRegExpNoCaptureMultiple(
Isolate* isolate,
Handle<String> subject,
Handle<JSRegExp> regexp,
Handle<JSArray> last_match_array,
FixedArrayBuilder* builder) {
ASSERT(subject->IsFlat());
+ ASSERT(regexp->CaptureCount() == 0);
int match_start = -1;
int match_end = 0;
int pos = 0;
- int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
- if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
+ int registers_per_match = RegExpImpl::IrregexpPrepare(regexp, subject);
+ if (registers_per_match < 0) return RegExpImpl::RE_EXCEPTION;
- OffsetsVector registers(required_registers, isolate);
+ int max_matches;
+ int num_registers = RegExpImpl::GlobalOffsetsVectorSize(regexp,
+ registers_per_match,
+ &max_matches);
+ OffsetsVector registers(num_registers, isolate);
Vector<int32_t> register_vector(registers.vector(), registers.length());
int subject_length = subject->length();
bool first = true;
-
for (;;) { // Break on failure, return on exception.
- RegExpImpl::IrregexpResult result =
- RegExpImpl::IrregexpExecOnce(regexp,
- subject,
- pos,
- register_vector);
- if (result == RegExpImpl::RE_SUCCESS) {
- match_start = register_vector[0];
- builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
- if (match_end < match_start) {
- ReplacementStringBuilder::AddSubjectSlice(builder,
- match_end,
- match_start);
+ int num_matches = RegExpImpl::IrregexpExecRaw(regexp,
+ subject,
+ pos,
+ register_vector);
+ if (num_matches > 0) {
+ for (int match_index = 0; match_index < num_matches; match_index++) {
+ int32_t* current_match = ®ister_vector[match_index * 2];
+ match_start = current_match[0];
+ builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
+ if (match_end < match_start) {
+ ReplacementStringBuilder::AddSubjectSlice(builder,
+ match_end,
+ match_start);
+ }
+ match_end = current_match[1];
+ HandleScope loop_scope(isolate);
+ if (!first) {
+ builder->Add(*isolate->factory()->NewProperSubString(subject,
+ match_start,
+ match_end));
+ } else {
+ builder->Add(*isolate->factory()->NewSubString(subject,
+ match_start,
+ match_end));
+ first = false;
+ }
}
- match_end = register_vector[1];
- HandleScope loop_scope(isolate);
- if (!first) {
- builder->Add(*isolate->factory()->NewProperSubString(subject,
- match_start,
- match_end));
- } else {
- builder->Add(*isolate->factory()->NewSubString(subject,
- match_start,
- match_end));
- }
+
+ // If we did not get the maximum number of matches, we can stop here
+ // since there are no matches left.
+ if (num_matches < max_matches) break;
+
if (match_start != match_end) {
pos = match_end;
} else {
pos = match_end + 1;
if (pos > subject_length) break;
}
- } else if (result == RegExpImpl::RE_FAILURE) {
+ } else if (num_matches == 0) {
break;
} else {
- ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
- return result;
+ ASSERT_EQ(num_matches, RegExpImpl::RE_EXCEPTION);
+ return RegExpImpl::RE_EXCEPTION;
}
- first = false;
}
if (match_start >= 0) {
if (match_end < subject_length) {
ReplacementStringBuilder::AddSubjectSlice(builder,
@@ -3870,108 +3890,121 @@
}
// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
// separate last match info. See comment on that function.
-static RegExpImpl::IrregexpResult SearchRegExpMultiple(
+static int SearchRegExpMultiple(
Isolate* isolate,
Handle<String> subject,
Handle<JSRegExp> regexp,
Handle<JSArray> last_match_array,
FixedArrayBuilder* builder) {
ASSERT(subject->IsFlat());
- int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
- if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
+ int registers_per_match = RegExpImpl::IrregexpPrepare(regexp, subject);
+ if (registers_per_match < 0) return RegExpImpl::RE_EXCEPTION;
- OffsetsVector registers(required_registers, isolate);
+ int max_matches;
+ int num_registers = RegExpImpl::GlobalOffsetsVectorSize(regexp,
+ registers_per_match,
+ &max_matches);
+ OffsetsVector registers(num_registers, isolate);
Vector<int32_t> register_vector(registers.vector(), registers.length());
- RegExpImpl::IrregexpResult result =
- RegExpImpl::IrregexpExecOnce(regexp,
- subject,
- 0,
- register_vector);
+ int num_matches = RegExpImpl::IrregexpExecRaw(regexp,
+ subject,
+ 0,
+ register_vector);
int capture_count = regexp->CaptureCount();
int subject_length = subject->length();
// Position to search from.
int pos = 0;
// End of previous match. Differs from pos if match was empty.
int match_end = 0;
- if (result == RegExpImpl::RE_SUCCESS) {
- bool first = true;
- do {
- int match_start = register_vector[0];
- builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
- if (match_end < match_start) {
- ReplacementStringBuilder::AddSubjectSlice(builder,
- match_end,
- match_start);
- }
- match_end = register_vector[1];
+ bool first = true;
- {
- // Avoid accumulating new handles inside loop.
- HandleScope temp_scope(isolate);
- // Arguments array to replace function is match, captures, index and
- // subject, i.e., 3 + capture count in total.
- Handle<FixedArray> elements =
- isolate->factory()->NewFixedArray(3 + capture_count);
- Handle<String> match;
- if (!first) {
- match = isolate->factory()->NewProperSubString(subject,
- match_start,
- match_end);
- } else {
- match = isolate->factory()->NewSubString(subject,
- match_start,
- match_end);
+ if (num_matches > 0) {
+ do {
+ int match_start = 0;
+ for (int match_index = 0; match_index < num_matches; match_index++) {
+ int32_t* current_match =
+ ®ister_vector[match_index * registers_per_match];
+ match_start = current_match[0];
+ builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
+ if (match_end < match_start) {
+ ReplacementStringBuilder::AddSubjectSlice(builder,
+ match_end,
+ match_start);
}
- elements->set(0, *match);
- for (int i = 1; i <= capture_count; i++) {
- int start = register_vector[i * 2];
- if (start >= 0) {
- int end = register_vector[i * 2 + 1];
- ASSERT(start <= end);
- Handle<String> substring;
- if (!first) {
- substring = isolate->factory()->NewProperSubString(subject,
- start,
- end);
+ match_end = current_match[1];
+
+ {
+ // Avoid accumulating new handles inside loop.
+ HandleScope temp_scope(isolate);
+ // Arguments array to replace function is match, captures, index and
+ // subject, i.e., 3 + capture count in total.
+ Handle<FixedArray> elements =
+ isolate->factory()->NewFixedArray(3 + capture_count);
+ Handle<String> match;
+ if (!first) {
+ match = isolate->factory()->NewProperSubString(subject,
+ match_start,
+ match_end);
+ } else {
+ match = isolate->factory()->NewSubString(subject,
+ match_start,
+ match_end);
+ }
+ elements->set(0, *match);
+ for (int i = 1; i <= capture_count; i++) {
+ int start = current_match[i * 2];
+ if (start >= 0) {
+ int end = current_match[i * 2 + 1];
+ ASSERT(start <= end);
+ Handle<String> substring;
+ if (!first) {
+ substring =
+ isolate->factory()->NewProperSubString(subject, start, end);
+ } else {
+ substring =
+ isolate->factory()->NewSubString(subject, start, end);
+ }
+ elements->set(i, *substring);
} else {
- substring = isolate->factory()->NewSubString(subject, start, end);
+ ASSERT(current_match[i * 2 + 1] < 0);
+ elements->set(i, isolate->heap()->undefined_value());
}
- elements->set(i, *substring);
- } else {
- ASSERT(register_vector[i * 2 + 1] < 0);
- elements->set(i, isolate->heap()->undefined_value());
}
+ elements->set(capture_count + 1, Smi::FromInt(match_start));
+ elements->set(capture_count + 2, *subject);
+ builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
}
- elements->set(capture_count + 1, Smi::FromInt(match_start));
- elements->set(capture_count + 2, *subject);
- builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
+ first = false;
}
+ // If we did not get the maximum number of matches, we can stop here
+ // since there are no matches left.
+ if (num_matches < max_matches) break;
+
if (match_end > match_start) {
pos = match_end;
} else {
pos = match_end + 1;
if (pos > subject_length) {
break;
}
}
- result = RegExpImpl::IrregexpExecOnce(regexp,
- subject,
- pos,
- register_vector);
- first = false;
- } while (result == RegExpImpl::RE_SUCCESS);
+ num_matches = RegExpImpl::IrregexpExecRaw(regexp,
+ subject,
+ pos,
+ register_vector);
+ } while (num_matches > 0);
- if (result != RegExpImpl::RE_EXCEPTION) {
+ if (num_matches != RegExpImpl::RE_EXCEPTION) {
// Finished matching, with at least one match.
if (match_end < subject_length) {
ReplacementStringBuilder::AddSubjectSlice(builder,
match_end,
subject_length);
@@ -3991,11 +4024,11 @@
RegExpImpl::SetLastInput(elements, *subject);
return RegExpImpl::RE_SUCCESS;
}
}
// No matches at all, return failure or exception result directly.
- return result;
+ return num_matches;
}
// This is only called for StringReplaceGlobalRegExpWithFunction. This sets
// lastMatchInfoOverride to maintain the last match info, so we don't need to
@@ -4008,14 +4041,14 @@
if (!subject->IsFlat()) FlattenString(subject);
CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
- ASSERT(last_match_info->HasFastElements());
+ ASSERT(last_match_info->HasFastObjectElements());
ASSERT(regexp->GetFlags().is_global());
Handle<FixedArray> result_elements;
- if (result_array->HasFastElements()) {
+ if (result_array->HasFastObjectElements()) {
result_elements =
Handle<FixedArray>(FixedArray::cast(result_array->elements()));
}
if (result_elements.is_null() || result_elements->length() < 16) {
result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
@@ -4033,11 +4066,11 @@
return isolate->heap()->null_value();
}
ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
- RegExpImpl::IrregexpResult result;
+ int result;
if (regexp->CaptureCount() == 0) {
result = SearchRegExpNoCaptureMultiple(isolate,
subject,
regexp,
last_match_info,
@@ -4313,21 +4346,26 @@
}
} else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
// JSObject without a string key. If the key is a Smi, check for a
// definite out-of-bounds access to elements, which is a strong indicator
// that subsequent accesses will also call the runtime. Proactively
- // transition elements to FAST_ELEMENTS to avoid excessive boxing of
+ // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
// doubles for those future calls in the case that the elements would
// become FAST_DOUBLE_ELEMENTS.
Handle<JSObject> js_object(args.at<JSObject>(0));
ElementsKind elements_kind = js_object->GetElementsKind();
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
- elements_kind == FAST_DOUBLE_ELEMENTS) {
+ if (IsFastElementsKind(elements_kind) &&
+ !IsFastObjectElementsKind(elements_kind)) {
FixedArrayBase* elements = js_object->elements();
if (args.at<Smi>(1)->value() >= elements->length()) {
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ elements_kind = FAST_HOLEY_ELEMENTS;
+ } else {
+ elements_kind = FAST_ELEMENTS;
+ }
MaybeObject* maybe_object = TransitionElements(js_object,
- FAST_ELEMENTS,
+ elements_kind,
isolate);
if (maybe_object->IsFailure()) return maybe_object;
}
}
}
@@ -4493,12 +4531,14 @@
// assignments.
if (js_object->IsStringObjectWithCharacterAt(index)) {
return *value;
}
+ js_object->ValidateElements();
Handle<Object> result = JSObject::SetElement(
js_object, index, value, attr, strict_mode, set_mode);
+ js_object->ValidateElements();
if (result.is_null()) return Failure::Exception();
return *value;
}
if (key->IsString()) {
@@ -4652,19 +4692,35 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 1);
Handle<Object> object = args.at<Object>(0);
- return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
+ if (object->IsJSObject()) {
+ Handle<JSObject> js_object(Handle<JSObject>::cast(object));
+ ElementsKind new_kind = js_object->HasFastHoleyElements()
+ ? FAST_HOLEY_DOUBLE_ELEMENTS
+ : FAST_DOUBLE_ELEMENTS;
+ return TransitionElements(object, new_kind, isolate);
+ } else {
+ return *object;
+ }
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 1);
Handle<Object> object = args.at<Object>(0);
- return TransitionElements(object, FAST_ELEMENTS, isolate);
+ if (object->IsJSObject()) {
+ Handle<JSObject> js_object(Handle<JSObject>::cast(object));
+ ElementsKind new_kind = js_object->HasFastHoleyElements()
+ ? FAST_HOLEY_ELEMENTS
+ : FAST_ELEMENTS;
+ return TransitionElements(object, new_kind, isolate);
+ } else {
+ return *object;
+ }
}
// Set the native flag on the function.
// This is used to decide if we should transform null and undefined
@@ -4691,36 +4747,42 @@
CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
CONVERT_SMI_ARG_CHECKED(literal_index, 4);
HandleScope scope;
Object* raw_boilerplate_object = literals->get(literal_index);
- Handle<JSArray> boilerplate(JSArray::cast(raw_boilerplate_object));
-#if DEBUG
+ Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
ElementsKind elements_kind = object->GetElementsKind();
-#endif
- ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
+ ASSERT(IsFastElementsKind(elements_kind));
// Smis should never trigger transitions.
ASSERT(!value->IsSmi());
if (value->IsNumber()) {
- ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
- JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
- if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
- FAST_DOUBLE_ELEMENTS)) {
- JSObject::TransitionElementsKind(boilerplate, FAST_DOUBLE_ELEMENTS);
+ ASSERT(IsFastSmiElementsKind(elements_kind));
+ ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
+ ? FAST_HOLEY_DOUBLE_ELEMENTS
+ : FAST_DOUBLE_ELEMENTS;
+ if (IsMoreGeneralElementsKindTransition(
+ boilerplate_object->GetElementsKind(),
+ transitioned_kind)) {
+ JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
}
- ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ JSObject::TransitionElementsKind(object, transitioned_kind);
+ ASSERT(IsFastDoubleElementsKind(object->GetElementsKind()));
FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
HeapNumber* number = HeapNumber::cast(*value);
double_array->set(store_index, number->Number());
} else {
- ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
- elements_kind == FAST_DOUBLE_ELEMENTS);
- JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
- if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
- FAST_ELEMENTS)) {
- JSObject::TransitionElementsKind(boilerplate, FAST_ELEMENTS);
+ ASSERT(IsFastSmiElementsKind(elements_kind) ||
+ IsFastDoubleElementsKind(elements_kind));
+ ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
+ ? FAST_HOLEY_ELEMENTS
+ : FAST_ELEMENTS;
+ JSObject::TransitionElementsKind(object, transitioned_kind);
+ if (IsMoreGeneralElementsKindTransition(
+ boilerplate_object->GetElementsKind(),
+ transitioned_kind)) {
+ JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
}
FixedArray* object_array = FixedArray::cast(object->elements());
object_array->set(store_index, *value);
}
return *object;
@@ -5929,11 +5991,13 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSArray, array, 0);
- if (!array->HasFastElements()) return isolate->heap()->undefined_value();
+ if (!array->HasFastObjectElements()) {
+ return isolate->heap()->undefined_value();
+ }
FixedArray* elements = FixedArray::cast(array->elements());
int n = elements->length();
bool ascii = true;
int total_length = 0;
@@ -6372,11 +6436,11 @@
Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
if (maybe_result->IsFailure()) return maybe_result;
result->set_length(Smi::FromInt(part_count));
- ASSERT(result->HasFastElements());
+ ASSERT(result->HasFastObjectElements());
if (part_count == 1 && indices.at(0) == subject_length) {
FixedArray::cast(result->elements())->set(0, *subject);
return *result;
}
@@ -6391,11 +6455,11 @@
elements->set(i, *substring);
part_start = part_end + pattern_length;
}
if (limit == 0xffffffffu) {
- if (result->HasFastElements()) {
+ if (result->HasFastObjectElements()) {
StringSplitCache::Enter(isolate->heap(),
isolate->heap()->string_split_cache(),
*subject,
*pattern,
*elements);
@@ -6748,11 +6812,11 @@
MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
if (maybe_result->IsFailure()) return maybe_result;
int special_length = special->length();
- if (!array->HasFastElements()) {
+ if (!array->HasFastObjectElements()) {
return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
if (fixed_array->length() < array_length) {
array_length = fixed_array->length();
@@ -6858,11 +6922,11 @@
return Failure::OutOfMemoryException();
}
int array_length = args.smi_at(1);
CONVERT_ARG_CHECKED(String, separator, 2);
- if (!array->HasFastElements()) {
+ if (!array->HasFastObjectElements()) {
return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
if (fixed_array->length() < array_length) {
array_length = fixed_array->length();
@@ -6975,12 +7039,11 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
- RUNTIME_ASSERT(elements_array->HasFastElements() ||
- elements_array->HasFastSmiOnlyElements());
+ RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
CONVERT_ARG_CHECKED(String, separator, 2);
// elements_array is fast-mode JSarray of alternating positions
// (increasing order) and strings.
// array_length is length of original array (used to add separators);
@@ -8275,10 +8338,23 @@
return isolate->heap()->undefined_value();
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ Code* unoptimized = function->shared()->code();
+ if (unoptimized->kind() == Code::FUNCTION) {
+ unoptimized->ClearInlineCaches();
+ unoptimized->ClearTypeFeedbackCells(isolate->heap());
+ }
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
#if defined(USE_SIMULATOR)
return isolate->heap()->true_value();
#else
return isolate->heap()->false_value();
@@ -9124,11 +9200,11 @@
CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
MaybeObject* maybe_result_array =
output->EnsureCanContainHeapObjectElements();
if (maybe_result_array->IsFailure()) return maybe_result_array;
- RUNTIME_ASSERT(output->HasFastElements());
+ RUNTIME_ASSERT(output->HasFastObjectElements());
AssertNoAllocation no_allocation;
FixedArray* output_array = FixedArray::cast(output->elements());
RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
@@ -9356,11 +9432,11 @@
// false otherwise.
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSArray, array, 0);
CONVERT_ARG_CHECKED(JSObject, element, 1);
- RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
+ RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
int length = Smi::cast(array->length())->value();
FixedArray* elements = FixedArray::cast(array->elements());
for (int i = 0; i < length; i++) {
if (elements->get(i) == element) return isolate->heap()->false_value();
}
@@ -9441,11 +9517,11 @@
Handle<Object> length =
isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
Handle<Map> map;
if (fast_elements_) {
map = isolate_->factory()->GetElementsTransitionMap(array,
- FAST_ELEMENTS);
+ FAST_HOLEY_ELEMENTS);
} else {
map = isolate_->factory()->GetElementsTransitionMap(array,
DICTIONARY_ELEMENTS);
}
array->set_map(*map);
@@ -9500,12 +9576,14 @@
static uint32_t EstimateElementCount(Handle<JSArray> array) {
uint32_t length = static_cast<uint32_t>(array->length()->Number());
int element_count = 0;
switch (array->GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
// Fast elements can't have lengths that are not representable by
// a 32-bit signed integer.
ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
int fast_length = static_cast<int>(length);
Handle<FixedArray> elements(FixedArray::cast(array->elements()));
@@ -9513,10 +9591,11 @@
if (!elements->get(i)->IsTheHole()) element_count++;
}
break;
}
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
// TODO(1810): Decide if it's worthwhile to implement this.
UNREACHABLE();
break;
case DICTIONARY_ELEMENTS: {
Handle<SeededNumberDictionary> dictionary(
@@ -9603,22 +9682,25 @@
static void CollectElementIndices(Handle<JSObject> object,
uint32_t range,
List<uint32_t>* indices) {
ElementsKind kind = object->GetElementsKind();
switch (kind) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
+ case FAST_SMI_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(object->elements()));
uint32_t length = static_cast<uint32_t>(elements->length());
if (range < length) length = range;
for (uint32_t i = 0; i < length; i++) {
if (!elements->get(i)->IsTheHole()) {
indices->Add(i);
}
}
break;
}
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
// TODO(1810): Decide if it's worthwhile to implement this.
UNREACHABLE();
break;
}
@@ -9729,12 +9811,14 @@
static bool IterateElements(Isolate* isolate,
Handle<JSArray> receiver,
ArrayConcatVisitor* visitor) {
uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
switch (receiver->GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
+ case FAST_SMI_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
// Run through the elements FixedArray and use HasElement and GetElement
// to check the prototype for missing elements.
Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
int fast_length = static_cast<int>(length);
ASSERT(fast_length <= elements->length());
@@ -9751,10 +9835,11 @@
visitor->visit(j, element_value);
}
}
break;
}
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
// TODO(1810): Decide if it's worthwhile to implement this.
UNREACHABLE();
break;
}
@@ -9848,11 +9933,11 @@
ASSERT(args.length() == 1);
HandleScope handle_scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
int argument_count = static_cast<int>(arguments->length()->Number());
- RUNTIME_ASSERT(arguments->HasFastElements());
+ RUNTIME_ASSERT(arguments->HasFastObjectElements());
Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
// Pass 1: estimate the length and number of elements of the result.
// The actual length can be larger if any of the arguments have getters
// that mutate other arguments (but will otherwise be precise).
@@ -9868,14 +9953,18 @@
uint32_t element_estimate;
if (obj->IsJSArray()) {
Handle<JSArray> array(Handle<JSArray>::cast(obj));
// TODO(1810): Find out if it's worthwhile to properly support
// arbitrary ElementsKinds. For now, pessimistically transition to
- // FAST_ELEMENTS.
+ // FAST_*_ELEMENTS.
if (array->HasFastDoubleElements()) {
+ ElementsKind to_kind = FAST_ELEMENTS;
+ if (array->HasFastHoleyElements()) {
+ to_kind = FAST_HOLEY_ELEMENTS;
+ }
array = Handle<JSArray>::cast(
- JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
+ JSObject::TransitionElementsKind(array, to_kind));
}
length_estimate =
static_cast<uint32_t>(array->length()->Number());
element_estimate =
EstimateElementCount(array);
@@ -9968,33 +10057,26 @@
// Move contents of argument 0 (an array) to argument 1 (an array)
RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSArray, from, 0);
CONVERT_ARG_CHECKED(JSArray, to, 1);
+ from->ValidateElements();
+ to->ValidateElements();
FixedArrayBase* new_elements = from->elements();
+ ElementsKind from_kind = from->GetElementsKind();
MaybeObject* maybe_new_map;
- ElementsKind elements_kind;
- if (new_elements->map() == isolate->heap()->fixed_array_map() ||
- new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
- elements_kind = FAST_ELEMENTS;
- } else if (new_elements->map() ==
- isolate->heap()->fixed_double_array_map()) {
- elements_kind = FAST_DOUBLE_ELEMENTS;
- } else {
- elements_kind = DICTIONARY_ELEMENTS;
- }
- maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
+ maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind);
Object* new_map;
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
- to->set_map(Map::cast(new_map));
- to->set_elements(new_elements);
+ to->set_map_and_elements(Map::cast(new_map), new_elements);
to->set_length(from->length());
Object* obj;
{ MaybeObject* maybe_obj = from->ResetElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
from->set_length(Smi::FromInt(0));
+ to->ValidateElements();
return to;
}
// How many elements does this object/array have?
@@ -10011,40 +10093,10 @@
return Smi::FromInt(FixedArray::cast(elements)->length());
}
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
- HandleScope handle_scope(isolate);
-
- ASSERT_EQ(3, args.length());
-
- CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
- Handle<Object> key1 = args.at<Object>(1);
- Handle<Object> key2 = args.at<Object>(2);
-
- uint32_t index1, index2;
- if (!key1->ToArrayIndex(&index1)
- || !key2->ToArrayIndex(&index2)) {
- return isolate->ThrowIllegalOperation();
- }
-
- Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
- Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
- RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
- Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
- RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
-
- RETURN_IF_EMPTY_HANDLE(
- isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
- RETURN_IF_EMPTY_HANDLE(
- isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
-
- return isolate->heap()->undefined_value();
-}
-
-
// Returns an array that tells you where in the [0, length) interval an array
// might have elements. Can either return keys (positive integers) or
// intervals (pair of a negative integer (-start-1) followed by a
// positive (length)) or undefined values.
// Intervals can span over some keys that are not in the object.
@@ -10070,12 +10122,11 @@
keys->set_undefined(i);
}
}
return *isolate->factory()->NewJSArrayWithElements(keys);
} else {
- ASSERT(array->HasFastElements() ||
- array->HasFastSmiOnlyElements() ||
+ ASSERT(array->HasFastSmiOrObjectElements() ||
array->HasFastDoubleElements());
Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
// -1 means start of array.
single_interval->set(0, Smi::FromInt(-1));
FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
@@ -13386,12 +13437,14 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
CONVERT_ARG_CHECKED(JSObject, obj, 0); \
return isolate->heap()->ToBoolean(obj->Has##Name()); \
}
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)