Version 3.25.25 (based on bleeding_edge revision r20239)
Roll ICU 239289:258359 and add support for external ICU data tables (issue 3142, Chromium issue 72633).
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@20247 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index ff54fa5..a376aaf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2014-03-25: Version 3.25.25
+
+ Roll ICU 239289:258359 and add support for external ICU data tables
+ (issue 3142, Chromium issue 72633).
+
+ Performance and stability improvements on all platforms.
+
+
2014-03-25: Version 3.25.24
Add support for per-isolate private symbols.
diff --git a/DEPS b/DEPS
index 66d21eb..353c5c8 100644
--- a/DEPS
+++ b/DEPS
@@ -8,7 +8,7 @@
"http://gyp.googlecode.com/svn/trunk@1831",
"v8/third_party/icu":
- "https://src.chromium.org/chrome/trunk/deps/third_party/icu46@239289",
+ "https://src.chromium.org/chrome/trunk/deps/third_party/icu46@258359",
}
deps_os = {
diff --git a/Makefile b/Makefile
index 6bd9bac..f390028 100644
--- a/Makefile
+++ b/Makefile
@@ -465,4 +465,4 @@
--revision 1831
svn checkout --force \
https://src.chromium.org/chrome/trunk/deps/third_party/icu46 \
- third_party/icu --revision 239289
+ third_party/icu --revision 258359
diff --git a/include/v8.h b/include/v8.h
index 3687485..6590ed5 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -4975,8 +4975,11 @@
/**
* Initialize the ICU library bundled with V8. The embedder should only
* invoke this method when using the bundled ICU. Returns true on success.
+ *
+ * If V8 was compiled with the ICU data in an external file, the location
+ * of the data file has to be provided.
*/
- static bool InitializeICU();
+ static bool InitializeICU(const char* icu_data_file = NULL);
/**
* Sets the v8::Platform to use. This should be invoked before V8 is
diff --git a/src/api.cc b/src/api.cc
index ca50778..f5ae10d 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -5112,8 +5112,8 @@
}
-bool v8::V8::InitializeICU() {
- return i::InitializeICU();
+bool v8::V8::InitializeICU(const char* icu_data_file) {
+ return i::InitializeICU(icu_data_file);
}
@@ -5403,6 +5403,8 @@
if (length == -1) length = StringLength(data);
i::Handle<i::String> result = NewString(
isolate->factory(), type, i::Vector<const Char>(data, length));
+ // We do not expect this to fail. Change this if it does.
+ CHECK(!result.is_null());
if (type == String::kUndetectableString) {
result->MarkAsUndetectable();
}
@@ -5460,8 +5462,8 @@
i::Handle<i::String> right_string = Utils::OpenHandle(*right);
i::Handle<i::String> result = isolate->factory()->NewConsString(left_string,
right_string);
- // We do not expect this to throw an exception. Change this if it does.
- CHECK_NOT_EMPTY_HANDLE(isolate, result);
+ // We do not expect this to fail. Change this if it does.
+ CHECK(!result.is_null());
return Utils::ToLocal(result);
}
@@ -5469,14 +5471,22 @@
static i::Handle<i::String> NewExternalStringHandle(
i::Isolate* isolate,
v8::String::ExternalStringResource* resource) {
- return isolate->factory()->NewExternalStringFromTwoByte(resource);
+ i::Handle<i::String> result =
+ isolate->factory()->NewExternalStringFromTwoByte(resource);
+ // We do not expect this to fail. Change this if it does.
+ CHECK(!result.is_null());
+ return result;
}
static i::Handle<i::String> NewExternalAsciiStringHandle(
i::Isolate* isolate,
v8::String::ExternalAsciiStringResource* resource) {
- return isolate->factory()->NewExternalStringFromAscii(resource);
+ i::Handle<i::String> result =
+ isolate->factory()->NewExternalStringFromAscii(resource);
+ // We do not expect this to fail. Change this if it does.
+ CHECK(!result.is_null());
+ return result;
}
@@ -7000,8 +7010,8 @@
i::Handle<i::String> cons = isolate->factory()->NewConsString(
isolate->factory()->InternalizeUtf8String(entry->name_prefix()),
isolate->factory()->InternalizeUtf8String(entry->name()));
- // We do not expect this to throw an exception. Change this if it does.
- CHECK_NOT_EMPTY_HANDLE(isolate, cons);
+ // We do not expect this to fail. Change this if it does.
+ CHECK(!cons.is_null());
return ToApiHandle<String>(cons);
}
}
diff --git a/src/arm64/assembler-arm64.h b/src/arm64/assembler-arm64.h
index 41eaaad..1aae2f2 100644
--- a/src/arm64/assembler-arm64.h
+++ b/src/arm64/assembler-arm64.h
@@ -588,22 +588,18 @@
CPURegister::RegisterType type_;
bool IsValid() const {
- if ((type_ == CPURegister::kRegister) ||
- (type_ == CPURegister::kFPRegister)) {
- bool is_valid = true;
- // Try to create a CPURegister for each element in the list.
- for (int i = 0; i < kRegListSizeInBits; i++) {
- if (((list_ >> i) & 1) != 0) {
- is_valid &= CPURegister::Create(i, size_, type_).IsValid();
- }
- }
- return is_valid;
- } else if (type_ == CPURegister::kNoRegister) {
- // The kNoRegister type is valid only for empty lists.
- // We can't use IsEmpty here because that asserts IsValid().
- return list_ == 0;
- } else {
- return false;
+ const RegList kValidRegisters = 0x8000000ffffffff;
+ const RegList kValidFPRegisters = 0x0000000ffffffff;
+ switch (type_) {
+ case CPURegister::kRegister:
+ return (list_ & kValidRegisters) == list_;
+ case CPURegister::kFPRegister:
+ return (list_ & kValidFPRegisters) == list_;
+ case CPURegister::kNoRegister:
+ return list_ == 0;
+ default:
+ UNREACHABLE();
+ return false;
}
}
};
diff --git a/src/ast.cc b/src/ast.cc
index 086d015..f6cf189 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -357,8 +357,7 @@
// Allocate a fixed array to hold all the object literals.
Handle<JSArray> array =
isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
- isolate->factory()->SetElementsCapacityAndLength(
- array, values()->length(), values()->length());
+ JSArray::Expand(array, values()->length());
// Fill in the literals.
bool is_simple = true;
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 7942c7f..b2a52cd 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -88,6 +88,8 @@
source.length());
Handle<String> source_code =
isolate_->factory()->NewExternalStringFromAscii(resource);
+ // We do not expect this to throw an exception. Change this if it does.
+ CHECK_NOT_EMPTY_HANDLE(isolate_, source_code);
heap->natives_source_cache()->set(index, *source_code);
}
Handle<Object> cached_source(heap->natives_source_cache()->get(index),
@@ -1463,6 +1465,7 @@
Handle<String> source_code =
factory->NewStringFromAscii(
ExperimentalNatives::GetRawScriptSource(index));
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, source_code, false);
return CompileNative(isolate, name, source_code);
}
@@ -1512,6 +1515,7 @@
if (cache == NULL || !cache->Lookup(name, &function_info)) {
ASSERT(source->IsOneByteRepresentation());
Handle<String> script_name = factory->NewStringFromUtf8(name);
+ ASSERT(!script_name.is_null());
function_info = Compiler::CompileScript(
source,
script_name,
@@ -2080,8 +2084,10 @@
ASSERT_EQ(".prototype", period_pos);
Vector<const char> property(holder_expr,
static_cast<int>(period_pos - holder_expr));
+ Handle<String> property_string = factory->InternalizeUtf8String(property);
+ ASSERT(!property_string.is_null());
Handle<JSFunction> function = Handle<JSFunction>::cast(
- GetProperty(isolate, global, factory->InternalizeUtf8String(property)));
+ GetProperty(isolate, global, property_string));
return Handle<JSObject>(JSObject::cast(function->prototype()));
}
@@ -2349,6 +2355,8 @@
}
Handle<String> source_code =
isolate->factory()->NewExternalStringFromAscii(extension->source());
+ // We do not expect this to throw an exception. Change this if it does.
+ CHECK_NOT_EMPTY_HANDLE(isolate, source_code);
bool result = CompileScriptCached(isolate,
CStrVector(extension->name()),
source_code,
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index 14dd1bd..e683a45 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -73,6 +73,7 @@
cache_->CopyTo(0, *new_array, 0, cache_->length());
cache_ = *new_array;
Handle<String> str = factory->NewStringFromAscii(name, TENURED);
+ ASSERT(!str.is_null());
cache_->set(length, *str);
cache_->set(length + 1, *shared);
Script::cast(shared->script())->set_type(Smi::FromInt(type_));
diff --git a/src/builtins.cc b/src/builtins.cc
index b73ed6b..e460a8f 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -506,23 +506,7 @@
uint32_t key,
Handle<FixedArrayBase> backing_store = Handle<FixedArrayBase>::null()) {
return accessor->HasElement(*receiver, *holder, key,
- backing_store.is_null() ? *backing_store : NULL);
-}
-
-
-// TODO(ishell): Temporary wrapper until handlified.
-static Handle<Object> ElementsAccessorGetWrapper(
- Isolate* isolate,
- ElementsAccessor* accessor,
- Handle<Object> receiver,
- Handle<JSObject> holder,
- uint32_t key,
- Handle<FixedArrayBase> backing_store = Handle<FixedArrayBase>::null()) {
- CALL_HEAP_FUNCTION(isolate,
- accessor->Get(*receiver, *holder, key,
- backing_store.is_null()
- ? *backing_store : NULL),
- Object);
+ backing_store.is_null() ? NULL : *backing_store);
}
@@ -544,8 +528,8 @@
Handle<Object> element;
if (ElementsAccessorHasElementWrapper(
accessor, array, array, new_length, elms_obj)) {
- element = ElementsAccessorGetWrapper(
- isolate, accessor, array, array, new_length, elms_obj);
+ element = accessor->Get(
+ array, array, new_length, elms_obj);
} else {
Handle<Object> proto(array->GetPrototype(), isolate);
element = Object::GetElement(isolate, proto, len - 1);
@@ -578,11 +562,12 @@
// Get first element
ElementsAccessor* accessor = array->GetElementsAccessor();
Handle<Object> first = accessor->Get(receiver, array, 0, elms_obj);
+ RETURN_IF_EMPTY_HANDLE(isolate, first);
if (first->IsTheHole()) {
first = isolate->factory()->undefined_value();
}
- if (!heap->lo_space()->Contains(*elms_obj)) {
+ if (!heap->CanMoveObjectStart(*elms_obj)) {
array->set_elements(LeftTrimFixedArray(heap, *elms_obj, 1));
} else {
// Shift the elements.
@@ -906,8 +891,24 @@
heap->MoveElements(*elms, delta, 0, actual_start);
}
- elms_obj = handle(LeftTrimFixedArray(heap, *elms_obj, delta));
-
+ if (heap->CanMoveObjectStart(*elms_obj)) {
+ // On the fast path we move the start of the object in memory.
+ elms_obj = handle(LeftTrimFixedArray(heap, *elms_obj, delta));
+ } else {
+ // This is the slow path. We are going to move the elements to the left
+ // by copying them. For trimmed values we store the hole.
+ if (elms_obj->IsFixedDoubleArray()) {
+ Handle<FixedDoubleArray> elms =
+ Handle<FixedDoubleArray>::cast(elms_obj);
+ MoveDoubleElements(*elms, 0, *elms, delta, len - delta);
+ FillWithHoles(*elms, len - delta, len);
+ } else {
+ Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
+ DisallowHeapAllocation no_gc;
+ heap->MoveElements(*elms, 0, delta, len - delta);
+ FillWithHoles(heap, *elms, len - delta, len);
+ }
+ }
elms_changed = true;
} else {
if (elms_obj->IsFixedDoubleArray()) {
diff --git a/src/contexts.cc b/src/contexts.cc
index ada6e04..33d47e9 100644
--- a/src/contexts.cc
+++ b/src/contexts.cc
@@ -368,7 +368,7 @@
Handle<Object> result(error_message_for_code_gen_from_strings(),
GetIsolate());
if (!result->IsUndefined()) return result;
- return GetIsolate()->factory()->NewStringFromAscii(i::CStrVector(
+ return GetIsolate()->factory()->NewStringFromOneByte(STATIC_ASCII_VECTOR(
"Code generation from strings disallowed for this context"));
}
diff --git a/src/d8.cc b/src/d8.cc
index d071105..7ac0c65 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1440,6 +1440,9 @@
} else if (strcmp(argv[i], "--throws") == 0) {
options.expected_to_throw = true;
argv[i] = NULL;
+ } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
+ options.icu_data_file = argv[i] + 16;
+ argv[i] = NULL;
}
#ifdef V8_SHARED
else if (strcmp(argv[i], "--dump-counters") == 0) {
@@ -1674,7 +1677,7 @@
int Shell::Main(int argc, char* argv[]) {
if (!SetOptions(argc, argv)) return 1;
- v8::V8::InitializeICU();
+ v8::V8::InitializeICU(options.icu_data_file);
#ifndef V8_SHARED
i::FLAG_trace_hydrogen_file = "hydrogen.cfg";
i::FLAG_redirect_code_traces_to = "code.asm";
diff --git a/src/d8.h b/src/d8.h
index db2edb9..3edd8a7 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -233,7 +233,8 @@
expected_to_throw(false),
mock_arraybuffer_allocator(false),
num_isolates(1),
- isolate_sources(NULL) { }
+ isolate_sources(NULL),
+ icu_data_file(NULL) { }
~ShellOptions() {
#ifndef V8_SHARED
@@ -258,6 +259,7 @@
bool mock_arraybuffer_allocator;
int num_isolates;
SourceGroup* isolate_sources;
+ const char* icu_data_file;
};
#ifdef V8_SHARED
diff --git a/src/debug.cc b/src/debug.cc
index c8a99d5..d7667f1 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -754,6 +754,7 @@
isolate->bootstrapper()->NativesSourceLookup(index);
Vector<const char> name = Natives::GetScriptName(index);
Handle<String> script_name = factory->NewStringFromAscii(name);
+ ASSERT(!script_name.is_null());
Handle<Context> context = isolate->native_context();
// Compile the script.
@@ -2599,6 +2600,7 @@
// Create the execution state object.
Handle<String> constructor_str =
isolate_->factory()->InternalizeUtf8String(constructor_name);
+ ASSERT(!constructor_str.is_null());
Handle<Object> constructor(
isolate_->global_object()->GetPropertyNoExceptionThrown(*constructor_str),
isolate_);
diff --git a/src/elements.cc b/src/elements.cc
index 527df6e..c8e28c5 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -766,14 +766,16 @@
Handle<Object> length,
Handle<FixedArrayBase> backing_store);
- MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(
- JSArray* array,
+ virtual void SetCapacityAndLength(
+ Handle<JSArray> array,
int capacity,
int length) V8_FINAL V8_OVERRIDE {
- return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
- array,
- capacity,
- length);
+ CALL_HEAP_FUNCTION_VOID(
+ array->GetIsolate(),
+ ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
+ *array,
+ capacity,
+ length));
}
MUST_USE_RESULT static MaybeObject* SetFastElementsCapacityAndLength(
@@ -784,6 +786,16 @@
return obj;
}
+ // TODO(ishell): Temporary wrapper until handlified.
+ MUST_USE_RESULT static Handle<Object> SetFastElementsCapacityAndLength(
+ Handle<JSObject> obj,
+ int capacity,
+ int length) {
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ SetFastElementsCapacityAndLength(*obj, capacity, length),
+ Object);
+ }
+
MUST_USE_RESULT virtual Handle<Object> Delete(
Handle<JSObject> obj,
uint32_t key,
@@ -978,28 +990,28 @@
// Adjusts the length of the fast backing store or returns the new length or
// undefined in case conversion to a slow backing store should be performed.
- static MaybeObject* SetLengthWithoutNormalize(FixedArrayBase* backing_store,
- JSArray* array,
- Object* length_object,
- uint32_t length) {
+ static Handle<Object> SetLengthWithoutNormalize(
+ Handle<FixedArrayBase> backing_store,
+ Handle<JSArray> array,
+ Handle<Object> length_object,
+ uint32_t length) {
+ Isolate* isolate = array->GetIsolate();
uint32_t old_capacity = backing_store->length();
- Object* old_length = array->length();
+ Handle<Object> old_length(array->length(), isolate);
bool same_or_smaller_size = old_length->IsSmi() &&
- static_cast<uint32_t>(Smi::cast(old_length)->value()) >= length;
+ static_cast<uint32_t>(Handle<Smi>::cast(old_length)->value()) >= length;
ElementsKind kind = array->GetElementsKind();
if (!same_or_smaller_size && IsFastElementsKind(kind) &&
!IsFastHoleyElementsKind(kind)) {
kind = GetHoleyElementsKind(kind);
- MaybeObject* maybe_obj = array->TransitionElementsKind(kind);
- if (maybe_obj->IsFailure()) return maybe_obj;
+ JSObject::TransitionElementsKind(array, kind);
}
// Check whether the backing store should be shrunk.
if (length <= old_capacity) {
if (array->HasFastSmiOrObjectElements()) {
- MaybeObject* maybe_obj = array->EnsureWritableFastElements();
- if (!maybe_obj->To(&backing_store)) return maybe_obj;
+ backing_store = JSObject::EnsureWritableFastElements(array);
}
if (2 * length <= old_capacity) {
// If more than half the elements won't be used, trim the array.
@@ -1016,7 +1028,7 @@
// Otherwise, fill the unused tail with holes.
int old_length = FastD2IChecked(array->length()->Number());
for (int i = length; i < old_length; i++) {
- BackingStore::cast(backing_store)->set_the_hole(i);
+ Handle<BackingStore>::cast(backing_store)->set_the_hole(i);
}
}
return length_object;
@@ -1026,27 +1038,14 @@
uint32_t min = JSObject::NewElementsCapacity(old_capacity);
uint32_t new_capacity = length > min ? length : min;
if (!array->ShouldConvertToSlowElements(new_capacity)) {
- MaybeObject* result = FastElementsAccessorSubclass::
+ FastElementsAccessorSubclass::
SetFastElementsCapacityAndLength(array, new_capacity, length);
- if (result->IsFailure()) return result;
array->ValidateElements();
return length_object;
}
// Request conversion to slow elements.
- return array->GetHeap()->undefined_value();
- }
-
- // TODO(ishell): Temporary wrapper until handlified.
- static Handle<Object> SetLengthWithoutNormalize(
- Handle<FixedArrayBase> backing_store,
- Handle<JSArray> array,
- Handle<Object> length_object,
- uint32_t length) {
- CALL_HEAP_FUNCTION(array->GetIsolate(),
- SetLengthWithoutNormalize(
- *backing_store, *array, *length_object, length),
- Object);
+ return isolate->factory()->undefined_value();
}
static Handle<Object> DeleteCommon(Handle<JSObject> obj,
@@ -1244,6 +1243,16 @@
length,
set_capacity_mode);
}
+
+ // TODO(ishell): Temporary wrapper until handlified.
+ static Handle<Object> SetFastElementsCapacityAndLength(
+ Handle<JSObject> obj,
+ int capacity,
+ int length) {
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ SetFastElementsCapacityAndLength(*obj, capacity, length),
+ Object);
+ }
};
@@ -1314,6 +1323,16 @@
length);
}
+ // TODO(ishell): Temporary wrapper until handlified.
+ static Handle<Object> SetFastElementsCapacityAndLength(
+ Handle<JSObject> obj,
+ int capacity,
+ int length) {
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ SetFastElementsCapacityAndLength(*obj, capacity, length),
+ Object);
+ }
+
protected:
static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
uint32_t from_start,
diff --git a/src/elements.h b/src/elements.h
index bd5e722..2ee07aa 100644
--- a/src/elements.h
+++ b/src/elements.h
@@ -126,9 +126,10 @@
// elements. This method should only be called for array expansion OR by
// runtime JavaScript code that use InternalArrays and don't care about
// EcmaScript 5.1 semantics.
- MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(JSArray* array,
- int capacity,
- int length) = 0;
+ virtual void SetCapacityAndLength(
+ Handle<JSArray> array,
+ int capacity,
+ int length) = 0;
// Deletes an element in an object, returning a new elements backing store.
MUST_USE_RESULT virtual Handle<Object> Delete(
diff --git a/src/factory.cc b/src/factory.cc
index 5e66202..e292455 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -289,7 +289,7 @@
Handle<SeqOneByteString> Factory::NewRawOneByteString(int length,
- PretenureFlag pretenure) {
+ PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateRawOneByteString(length, pretenure),
@@ -411,6 +411,7 @@
ASSERT(left->IsFlat());
ASSERT(right->IsFlat());
+ STATIC_ASSERT(ConsString::kMinLength <= String::kMaxLength);
if (is_one_byte) {
Handle<SeqOneByteString> result = NewRawOneByteString(length);
DisallowHeapAllocation no_gc;
@@ -496,12 +497,14 @@
if (!FLAG_string_slices || length < SlicedString::kMinLength) {
if (str->IsOneByteRepresentation()) {
Handle<SeqOneByteString> result = NewRawOneByteString(length);
+ ASSERT(!result.is_null());
uint8_t* dest = result->GetChars();
DisallowHeapAllocation no_gc;
String::WriteToFlat(*str, dest, begin, end);
return result;
} else {
Handle<SeqTwoByteString> result = NewRawTwoByteString(length);
+ ASSERT(!result.is_null());
uc16* dest = result->GetChars();
DisallowHeapAllocation no_gc;
String::WriteToFlat(*str, dest, begin, end);
@@ -1486,16 +1489,6 @@
}
-void Factory::SetElementsCapacityAndLength(Handle<JSArray> array,
- int capacity,
- int length) {
- ElementsAccessor* accessor = array->GetElementsAccessor();
- CALL_HEAP_FUNCTION_VOID(
- isolate(),
- accessor->SetCapacityAndLength(*array, capacity, length));
-}
-
-
Handle<JSGeneratorObject> Factory::NewJSGeneratorObject(
Handle<JSFunction> function) {
ASSERT(function->shared()->is_generator());
diff --git a/src/factory.h b/src/factory.h
index 5562ef4..e57e130 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -387,10 +387,6 @@
int capacity,
ArrayStorageAllocationMode mode = DONT_INITIALIZE_ARRAY_ELEMENTS);
- void SetElementsCapacityAndLength(Handle<JSArray> array,
- int capacity,
- int length);
-
Handle<JSGeneratorObject> NewJSGeneratorObject(Handle<JSFunction> function);
Handle<JSArrayBuffer> NewJSArrayBuffer();
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 3b9ebb3..2d2cadf 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -276,6 +276,7 @@
DEFINE_string(trace_phase, "HLZ", "trace generated IR for specified phases")
DEFINE_bool(trace_inlining, false, "trace inlining decisions")
DEFINE_bool(trace_load_elimination, false, "trace load elimination")
+DEFINE_bool(trace_store_elimination, false, "trace store elimination")
DEFINE_bool(trace_alloc, false, "trace register allocator")
DEFINE_bool(trace_all_uses, false, "trace all use positions")
DEFINE_bool(trace_range, false, "trace range analysis")
@@ -311,6 +312,7 @@
"analyze liveness of environment slots and zap dead values")
DEFINE_bool(load_elimination, true, "use load elimination")
DEFINE_bool(check_elimination, true, "use check elimination")
+DEFINE_bool(store_elimination, false, "use store elimination")
DEFINE_bool(dead_code_elimination, true, "use dead code elimination")
DEFINE_bool(fold_constants, true, "use constant folding")
DEFINE_bool(trace_dead_code_elimination, false, "trace dead code elimination")
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 7e465d5..063cf30 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -138,7 +138,7 @@
MaybeObject* Heap::AllocateOneByteInternalizedString(Vector<const uint8_t> str,
uint32_t hash_field) {
if (str.length() > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+ return isolate()->ThrowInvalidStringLength();
}
// Compute map and object size.
Map* map = ascii_internalized_string_map();
@@ -171,7 +171,7 @@
MaybeObject* Heap::AllocateTwoByteInternalizedString(Vector<const uc16> str,
uint32_t hash_field) {
if (str.length() > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+ return isolate()->ThrowInvalidStringLength();
}
// Compute map and object size.
Map* map = internalized_string_map();
diff --git a/src/heap.cc b/src/heap.cc
index e785629..eae7241 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -154,7 +154,6 @@
configured_(false),
external_string_table_(this),
chunks_queued_for_free_(NULL),
- relocation_mutex_(NULL),
gc_callbacks_depth_(0) {
// Allow build-time customization of the max semispace size. Building
// V8 with snapshots and a non-default max semispace size is much
@@ -3866,7 +3865,7 @@
const ExternalAsciiString::Resource* resource) {
size_t length = resource->length();
if (length > static_cast<size_t>(String::kMaxLength)) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+ return isolate()->ThrowInvalidStringLength();
}
Map* map = external_ascii_string_map();
@@ -3888,7 +3887,7 @@
const ExternalTwoByteString::Resource* resource) {
size_t length = resource->length();
if (length > static_cast<size_t>(String::kMaxLength)) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+ return isolate()->ThrowInvalidStringLength();
}
// For small strings we check whether the resource contains only
@@ -3969,6 +3968,21 @@
}
+bool Heap::CanMoveObjectStart(HeapObject* object) {
+ Address address = object->address();
+ bool is_in_old_pointer_space = InOldPointerSpace(address);
+ bool is_in_old_data_space = InOldDataSpace(address);
+
+ if (lo_space()->Contains(object)) return false;
+
+ // We cannot move the object start if the given old space page is
+ // concurrently swept.
+ return (!is_in_old_pointer_space && !is_in_old_data_space) ||
+ Page::FromAddress(address)->parallel_sweeping() <=
+ MemoryChunk::PARALLEL_SWEEPING_FINALIZE;
+}
+
+
void Heap::AdjustLiveBytes(Address address, int by, InvocationMode mode) {
if (incremental_marking()->IsMarking() &&
Marking::IsBlack(Marking::MarkBitFrom(address))) {
@@ -4973,8 +4987,8 @@
int size;
Map* map;
- if (chars > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+ if (chars < 0 || chars > String::kMaxLength) {
+ return isolate()->ThrowInvalidStringLength();
}
if (is_one_byte) {
map = ascii_internalized_string_map();
@@ -5022,7 +5036,7 @@
MaybeObject* Heap::AllocateRawOneByteString(int length,
PretenureFlag pretenure) {
if (length < 0 || length > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+ return isolate()->ThrowInvalidStringLength();
}
int size = SeqOneByteString::SizeFor(length);
ASSERT(size <= SeqOneByteString::kMaxSize);
@@ -5046,7 +5060,7 @@
MaybeObject* Heap::AllocateRawTwoByteString(int length,
PretenureFlag pretenure) {
if (length < 0 || length > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+ return isolate()->ThrowInvalidStringLength();
}
int size = SeqTwoByteString::SizeFor(length);
ASSERT(size <= SeqTwoByteString::kMaxSize);
@@ -6595,8 +6609,6 @@
mark_compact_collector()->SetUp();
- if (FLAG_concurrent_recompilation) relocation_mutex_ = new Mutex;
-
return true;
}
@@ -6738,9 +6750,6 @@
incremental_marking()->TearDown();
isolate_->memory_allocator()->TearDown();
-
- delete relocation_mutex_;
- relocation_mutex_ = NULL;
}
diff --git a/src/heap.h b/src/heap.h
index f6cd3eb..fde95ce 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -1177,6 +1177,8 @@
// when shortening objects.
void CreateFillerObjectAt(Address addr, int size);
+ bool CanMoveObjectStart(HeapObject* object);
+
enum InvocationMode { FROM_GC, FROM_MUTATOR };
// Maintain marking consistency for IncrementalMarking.
@@ -1906,16 +1908,12 @@
class RelocationLock {
public:
explicit RelocationLock(Heap* heap) : heap_(heap) {
- if (FLAG_concurrent_recompilation) {
- heap_->relocation_mutex_->Lock();
- }
+ heap_->relocation_mutex_.Lock();
}
~RelocationLock() {
- if (FLAG_concurrent_recompilation) {
- heap_->relocation_mutex_->Unlock();
- }
+ heap_->relocation_mutex_.Unlock();
}
private:
@@ -2518,7 +2516,7 @@
MemoryChunk* chunks_queued_for_free_;
- Mutex* relocation_mutex_;
+ Mutex relocation_mutex_;
int gc_callbacks_depth_;
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index cfe5f1a..b822d84 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -841,6 +841,107 @@
#endif
+static bool HasPrimitiveRepresentation(HValue* instr) {
+ return instr->representation().IsInteger32() ||
+ instr->representation().IsDouble();
+}
+
+
+bool HInstruction::CanDeoptimize() {
+ // TODO(titzer): make this a virtual method?
+ switch (opcode()) {
+ case HValue::kAccessArgumentsAt:
+ case HValue::kApplyArguments:
+ case HValue::kArgumentsElements:
+ case HValue::kArgumentsLength:
+ case HValue::kArgumentsObject:
+ case HValue::kBoundsCheckBaseIndexInformation:
+ case HValue::kCapturedObject:
+ case HValue::kClampToUint8:
+ case HValue::kConstant:
+ case HValue::kContext:
+ case HValue::kDateField:
+ case HValue::kDebugBreak:
+ case HValue::kDeclareGlobals:
+ case HValue::kDiv:
+ case HValue::kDummyUse:
+ case HValue::kEnterInlined:
+ case HValue::kEnvironmentMarker:
+ case HValue::kForInCacheArray:
+ case HValue::kForInPrepareMap:
+ case HValue::kFunctionLiteral:
+ case HValue::kGetCachedArrayIndex:
+ case HValue::kGoto:
+ case HValue::kInnerAllocatedObject:
+ case HValue::kInstanceOf:
+ case HValue::kInstanceOfKnownGlobal:
+ case HValue::kInvokeFunction:
+ case HValue::kLeaveInlined:
+ case HValue::kLoadContextSlot:
+ case HValue::kLoadFieldByIndex:
+ case HValue::kLoadFunctionPrototype:
+ case HValue::kLoadGlobalCell:
+ case HValue::kLoadGlobalGeneric:
+ case HValue::kLoadKeyed:
+ case HValue::kLoadKeyedGeneric:
+ case HValue::kLoadNamedField:
+ case HValue::kLoadNamedGeneric:
+ case HValue::kLoadRoot:
+ case HValue::kMapEnumLength:
+ case HValue::kMathFloorOfDiv:
+ case HValue::kMathMinMax:
+ case HValue::kMod:
+ case HValue::kMul:
+ case HValue::kOsrEntry:
+ case HValue::kParameter:
+ case HValue::kPower:
+ case HValue::kPushArgument:
+ case HValue::kRor:
+ case HValue::kSar:
+ case HValue::kSeqStringGetChar:
+ case HValue::kSeqStringSetChar:
+ case HValue::kShl:
+ case HValue::kShr:
+ case HValue::kSimulate:
+ case HValue::kStackCheck:
+ case HValue::kStoreCodeEntry:
+ case HValue::kStoreContextSlot:
+ case HValue::kStoreGlobalCell:
+ case HValue::kStoreKeyed:
+ case HValue::kStoreKeyedGeneric:
+ case HValue::kStoreNamedField:
+ case HValue::kStoreNamedGeneric:
+ case HValue::kStringAdd:
+ case HValue::kStringCharCodeAt:
+ case HValue::kStringCharFromCode:
+ case HValue::kSub:
+ case HValue::kThisFunction:
+ case HValue::kToFastProperties:
+ case HValue::kTransitionElementsKind:
+ case HValue::kTrapAllocationMemento:
+ case HValue::kTypeof:
+ case HValue::kUnaryMathOperation:
+ case HValue::kUseConst:
+ case HValue::kWrapReceiver:
+ return false;
+ case HValue::kForceRepresentation:
+ case HValue::kAdd:
+ case HValue::kBitwise:
+ case HValue::kChange:
+ case HValue::kCompareGeneric:
+ // These instructions might deoptimize if they are not primitive.
+ if (!HasPrimitiveRepresentation(this)) return true;
+ for (int i = 0; i < OperandCount(); i++) {
+ HValue* input = OperandAt(i);
+ if (!HasPrimitiveRepresentation(input)) return true;
+ }
+ return false;
+ default:
+ return true;
+ }
+}
+
+
void HDummyUse::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
}
@@ -3923,9 +4024,15 @@
HConstant* c_right = HConstant::cast(right);
HConstant* c_left = HConstant::cast(left);
if (c_left->HasStringValue() && c_right->HasStringValue()) {
- Handle<String> concat = zone->isolate()->factory()->NewFlatConcatString(
- c_left->StringValue(), c_right->StringValue());
- return HConstant::New(zone, context, concat);
+ Handle<String> left_string = c_left->StringValue();
+ Handle<String> right_string = c_right->StringValue();
+ // Prevent possible exception by invalid string length.
+ if (left_string->length() + right_string->length() < String::kMaxLength) {
+ Handle<String> concat = zone->isolate()->factory()->NewFlatConcatString(
+ c_left->StringValue(), c_right->StringValue());
+ ASSERT(!concat.is_null());
+ return HConstant::New(zone, context, concat);
+ }
}
}
return new(zone) HStringAdd(
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 109cff0..d22cc32 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -1271,6 +1271,8 @@
virtual void Verify() V8_OVERRIDE;
#endif
+ bool CanDeoptimize();
+
virtual bool HasStackCheck() { return false; }
DECLARE_ABSTRACT_INSTRUCTION(Instruction)
diff --git a/src/hydrogen-store-elimination.cc b/src/hydrogen-store-elimination.cc
new file mode 100644
index 0000000..2e6ee51
--- /dev/null
+++ b/src/hydrogen-store-elimination.cc
@@ -0,0 +1,139 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "hydrogen-store-elimination.h"
+#include "hydrogen-instructions.h"
+
+namespace v8 {
+namespace internal {
+
+#define TRACE(x) if (FLAG_trace_store_elimination) PrintF x
+
+// Performs a block-by-block local analysis for removable stores.
+void HStoreEliminationPhase::Run() {
+ GVNFlagSet flags; // Use GVN flags as an approximation for some instructions.
+ flags.RemoveAll();
+
+ flags.Add(kArrayElements);
+ flags.Add(kArrayLengths);
+ flags.Add(kStringLengths);
+ flags.Add(kBackingStoreFields);
+ flags.Add(kDoubleArrayElements);
+ flags.Add(kDoubleFields);
+ flags.Add(kElementsPointer);
+ flags.Add(kInobjectFields);
+ flags.Add(kExternalMemory);
+ flags.Add(kStringChars);
+ flags.Add(kTypedArrayElements);
+
+ for (int i = 0; i < graph()->blocks()->length(); i++) {
+ unobserved_.Rewind(0);
+ HBasicBlock* block = graph()->blocks()->at(i);
+ for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
+ HInstruction* instr = it.Current();
+
+ // TODO(titzer): eliminate unobserved HStoreKeyed instructions too.
+ switch (instr->opcode()) {
+ case HValue::kStoreNamedField:
+ // Remove any unobserved stores overwritten by this store.
+ ProcessStore(HStoreNamedField::cast(instr));
+ break;
+ case HValue::kLoadNamedField:
+ // Observe any unobserved stores on this object + field.
+ ProcessLoad(HLoadNamedField::cast(instr));
+ break;
+ default:
+ ProcessInstr(instr, flags);
+ break;
+ }
+ }
+ }
+}
+
+
+void HStoreEliminationPhase::ProcessStore(HStoreNamedField* store) {
+ HValue* object = store->object()->ActualValue();
+ int i = 0;
+ while (i < unobserved_.length()) {
+ HStoreNamedField* prev = unobserved_.at(i);
+ if (aliasing_->MustAlias(object, prev->object()->ActualValue()) &&
+ store->access().Equals(prev->access())) {
+ // This store is guaranteed to overwrite the previous store.
+ prev->DeleteAndReplaceWith(NULL);
+ TRACE(("++ Unobserved store S%d overwritten by S%d\n",
+ prev->id(), store->id()));
+ unobserved_.Remove(i);
+ } else {
+ // TODO(titzer): remove map word clearing from folded allocations.
+ i++;
+ }
+ }
+ // Only non-transitioning stores are removable.
+ if (!store->has_transition()) {
+ TRACE(("-- Might remove store S%d\n", store->id()));
+ unobserved_.Add(store, zone());
+ }
+}
+
+
+void HStoreEliminationPhase::ProcessLoad(HLoadNamedField* load) {
+ HValue* object = load->object()->ActualValue();
+ int i = 0;
+ while (i < unobserved_.length()) {
+ HStoreNamedField* prev = unobserved_.at(i);
+ if (aliasing_->MayAlias(object, prev->object()->ActualValue()) &&
+ load->access().Equals(prev->access())) {
+ TRACE(("-- Observed store S%d by load L%d\n", prev->id(), load->id()));
+ unobserved_.Remove(i);
+ } else {
+ i++;
+ }
+ }
+}
+
+
+void HStoreEliminationPhase::ProcessInstr(HInstruction* instr,
+ GVNFlagSet flags) {
+ if (unobserved_.length() == 0) return; // Nothing to do.
+ if (instr->CanDeoptimize()) {
+ TRACE(("-- Observed stores at I%d (might deoptimize)\n", instr->id()));
+ unobserved_.Rewind(0);
+ return;
+ }
+ if (instr->CheckChangesFlag(kNewSpacePromotion)) {
+ TRACE(("-- Observed stores at I%d (might GC)\n", instr->id()));
+ unobserved_.Rewind(0);
+ return;
+ }
+ if (instr->ChangesFlags().ContainsAnyOf(flags)) {
+ TRACE(("-- Observed stores at I%d (GVN flags)\n", instr->id()));
+ unobserved_.Rewind(0);
+ return;
+ }
+}
+
+} } // namespace v8::internal
diff --git a/src/hydrogen-store-elimination.h b/src/hydrogen-store-elimination.h
new file mode 100644
index 0000000..7dc871c
--- /dev/null
+++ b/src/hydrogen-store-elimination.h
@@ -0,0 +1,57 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HYDROGEN_STORE_ELIMINATION_H_
+#define V8_HYDROGEN_STORE_ELIMINATION_H_
+
+#include "hydrogen.h"
+#include "hydrogen-alias-analysis.h"
+
+namespace v8 {
+namespace internal {
+
+class HStoreEliminationPhase : public HPhase {
+ public:
+ explicit HStoreEliminationPhase(HGraph* graph)
+ : HPhase("H_Store elimination", graph),
+ unobserved_(10, zone()),
+ aliasing_() { }
+
+ void Run();
+ private:
+ ZoneList<HStoreNamedField*> unobserved_;
+ HAliasAnalyzer* aliasing_;
+
+ void ProcessStore(HStoreNamedField* store);
+ void ProcessLoad(HLoadNamedField* load);
+ void ProcessInstr(HInstruction* instr, GVNFlagSet flags);
+};
+
+
+} } // namespace v8::internal
+
+#endif
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 45d4b56..c669cc2 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -54,6 +54,7 @@
#include "hydrogen-removable-simulates.h"
#include "hydrogen-representation-changes.h"
#include "hydrogen-sce.h"
+#include "hydrogen-store-elimination.h"
#include "hydrogen-uint32-analysis.h"
#include "lithium-allocator.h"
#include "parser.h"
@@ -4039,6 +4040,8 @@
if (FLAG_check_elimination) Run<HCheckEliminationPhase>();
+ if (FLAG_store_elimination) Run<HStoreEliminationPhase>();
+
Run<HRangeAnalysisPhase>();
Run<HComputeChangeUndefinedToNaN>();
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index de3bf9e..696c6be 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1005,30 +1005,22 @@
LInstruction* goto_instr = CheckElideControlInstruction(instr);
if (goto_instr != NULL) return goto_instr;
- ToBooleanStub::Types expected = instr->expected_input_types();
-
- // Tagged values that are not known smis or booleans require a
- // deoptimization environment. If the instruction is generic no
- // environment is needed since all cases are handled.
HValue* value = instr->value();
- Representation rep = value->representation();
+ Representation r = value->representation();
HType type = value->type();
- if (!rep.IsTagged() || type.IsSmi() || type.IsBoolean()) {
- return new(zone()) LBranch(UseRegister(value), NULL);
+ ToBooleanStub::Types expected = instr->expected_input_types();
+ if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
+
+ bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
+ type.IsJSArray() || type.IsHeapNumber() || type.IsString();
+ LOperand* temp = !easy_case && expected.NeedsMap() ? TempRegister() : NULL;
+ LInstruction* branch = new(zone()) LBranch(UseRegister(value), temp);
+ if (!easy_case &&
+ ((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
+ !expected.IsGeneric())) {
+ branch = AssignEnvironment(branch);
}
-
- bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
- LOperand* temp = needs_temp ? TempRegister() : NULL;
-
- // The Generic stub does not have a deopt, so we need no environment.
- if (expected.IsGeneric()) {
- return new(zone()) LBranch(UseRegister(value), temp);
- }
-
- // We need a temporary register when we have to access the map *or* we have
- // no type info yet, in which case we handle all cases (including the ones
- // involving maps).
- return AssignEnvironment(new(zone()) LBranch(UseRegister(value), temp));
+ return branch;
}
@@ -1221,8 +1213,12 @@
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
LOperand* context = UseAny(instr->context()); // Deferred use.
LOperand* input = UseRegisterAtStart(instr->value());
- LMathAbs* result = new(zone()) LMathAbs(context, input);
- return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+ LInstruction* result =
+ DefineSameAsFirst(new(zone()) LMathAbs(context, input));
+ Representation r = instr->value()->representation();
+ if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
+ if (!r.IsDouble()) result = AssignEnvironment(result);
+ return result;
}
@@ -1901,8 +1897,12 @@
LOperand* value = UseRegister(instr->value());
// Temp register only necessary for minus zero check.
LOperand* temp = TempRegister();
- LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
- return AssignEnvironment(DefineAsRegister(res));
+ LInstruction* result = DefineAsRegister(
+ new(zone()) LNumberUntagD(value, temp));
+ if (!instr->value()->representation().IsSmi()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
} else if (to.IsSmi()) {
HValue* val = instr->value();
LOperand* value = UseRegister(val);
@@ -1921,8 +1921,13 @@
LOperand* xmm_temp =
(CpuFeatures::IsSafeForSnapshot(SSE2) && !truncating)
? FixedTemp(xmm1) : NULL;
- LTaggedToI* res = new(zone()) LTaggedToI(UseRegister(val), xmm_temp);
- return AssignEnvironment(DefineSameAsFirst(res));
+ LInstruction* result = DefineSameAsFirst(
+ new(zone()) LTaggedToI(UseRegister(val), xmm_temp));
+ if (!instr->value()->representation().IsSmi()) {
+ // Note: Only deopts in deferred code.
+ result = AssignEnvironment(result);
+ }
+ return result;
}
}
} else if (from.IsDouble()) {
@@ -1946,8 +1951,10 @@
LOperand* value = needs_temp ?
UseTempRegister(instr->value()) : UseRegister(instr->value());
LOperand* temp = needs_temp ? TempRegister() : NULL;
- return AssignEnvironment(
- DefineAsRegister(new(zone()) LDoubleToI(value, temp)));
+ LInstruction* result =
+ DefineAsRegister(new(zone()) LDoubleToI(value, temp));
+ if (!truncating) result = AssignEnvironment(result);
+ return result;
}
} else if (from.IsInteger32()) {
info()->MarkAsDeferredCalling();
@@ -1961,11 +1968,11 @@
LOperand* temp2 = CpuFeatures::IsSupported(SSE2) ? FixedTemp(xmm1)
: NULL;
LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
- return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+ return AssignPointerMap(DefineSameAsFirst(result));
} else {
LOperand* temp = TempRegister();
LNumberTagI* result = new(zone()) LNumberTagI(value, temp);
- return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+ return AssignPointerMap(DefineSameAsFirst(result));
}
} else if (to.IsSmi()) {
HValue* val = instr->value();
@@ -2031,6 +2038,7 @@
}
LCheckMaps* result = new(zone()) LCheckMaps(value);
if (!instr->CanOmitMapChecks()) {
+ // Note: Only deopts in deferred code.
AssignEnvironment(result);
if (instr->has_migration_target()) return AssignPointerMap(result);
}
@@ -2139,7 +2147,10 @@
LOperand* context = UseRegisterAtStart(instr->value());
LInstruction* result =
DefineAsRegister(new(zone()) LLoadContextSlot(context));
- return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
+ if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
@@ -2155,7 +2166,10 @@
temp = NULL;
}
LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
- return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
+ if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
@@ -2197,11 +2211,11 @@
LOperand* key = clobbers_key
? UseTempRegister(instr->key())
: UseRegisterOrConstantAtStart(instr->key());
- LLoadKeyed* result = NULL;
+ LInstruction* result = NULL;
if (!instr->is_typed_elements()) {
LOperand* obj = UseRegisterAtStart(instr->elements());
- result = new(zone()) LLoadKeyed(obj, key);
+ result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key));
} else {
ASSERT(
(instr->representation().IsInteger32() &&
@@ -2209,15 +2223,20 @@
(instr->representation().IsDouble() &&
(IsDoubleOrFloatElementsKind(instr->elements_kind()))));
LOperand* backing_store = UseRegister(instr->elements());
- result = new(zone()) LLoadKeyed(backing_store, key);
+ result = DefineAsRegister(new(zone()) LLoadKeyed(backing_store, key));
}
- DefineAsRegister(result);
- bool can_deoptimize = instr->RequiresHoleCheck() ||
- (elements_kind == EXTERNAL_UINT32_ELEMENTS);
- // An unsigned int array load might overflow and cause a deopt, make sure it
- // has an environment.
- return can_deoptimize ? AssignEnvironment(result) : result;
+ if ((instr->is_external() || instr->is_fixed_typed_array()) ?
+ // see LCodeGen::DoLoadKeyedExternalArray
+ ((instr->elements_kind() == EXTERNAL_UINT32_ELEMENTS ||
+ instr->elements_kind() == UINT32_ELEMENTS) &&
+ !instr->CheckFlag(HInstruction::kUint32)) :
+ // see LCodeGen::DoLoadKeyedFixedDoubleArray and
+ // LCodeGen::DoLoadKeyedFixedArray
+ instr->RequiresHoleCheck()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
@@ -2408,12 +2427,14 @@
// We need a temporary register for write barrier of the map field.
LOperand* temp_map = needs_write_barrier_for_map ? TempRegister() : NULL;
- LStoreNamedField* result =
+ LInstruction* result =
new(zone()) LStoreNamedField(obj, val, temp, temp_map);
- if (instr->field_representation().IsHeapObject()) {
- if (!instr->value()->type().IsHeapObject()) {
- return AssignEnvironment(result);
- }
+ if (!instr->access().IsExternalMemory() &&
+ instr->field_representation().IsHeapObject() &&
+ (val->IsConstantOperand()
+ ? HConstant::cast(instr->value())->HasSmiValue()
+ : !instr->value()->type().IsHeapObject())) {
+ result = AssignEnvironment(result);
}
return result;
}
@@ -2445,7 +2466,7 @@
LOperand* context = UseAny(instr->context());
LStringCharCodeAt* result =
new(zone()) LStringCharCodeAt(context, string, index);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ return AssignPointerMap(DefineAsRegister(result));
}
diff --git a/src/icu_util.cc b/src/icu_util.cc
index b9bd65e..6441dbd 100644
--- a/src/icu_util.cc
+++ b/src/icu_util.cc
@@ -27,12 +27,20 @@
#include "icu_util.h"
-#if defined(_WIN32) && defined(V8_I18N_SUPPORT)
+#if defined(_WIN32)
#include <windows.h>
+#endif
+
+#if defined(V8_I18N_SUPPORT)
+#include <stdio.h>
#include "unicode/putil.h"
#include "unicode/udata.h"
+#define ICU_UTIL_DATA_FILE 0
+#define ICU_UTIL_DATA_SHARED 1
+#define ICU_UTIL_DATA_STATIC 2
+
#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll"
#endif
@@ -41,8 +49,11 @@
namespace internal {
-bool InitializeICU() {
-#if defined(_WIN32) && defined(V8_I18N_SUPPORT)
+bool InitializeICU(const char* icu_data_file) {
+#if !defined(V8_I18N_SUPPORT)
+ return true;
+#else
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
// We expect to find the ICU data module alongside the current module.
HMODULE module = LoadLibraryA(ICU_UTIL_DATA_SHARED_MODULE_NAME);
if (!module) return false;
@@ -53,9 +64,30 @@
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(reinterpret_cast<void*>(addr), &err);
return err == U_ZERO_ERROR;
-#else
+#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC
// Mac/Linux bundle the ICU data in.
return true;
+#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+ if (!icu_data_file) return false;
+
+ FILE* inf = fopen(icu_data_file, "rb");
+ if (!inf) return false;
+
+ fseek(inf, 0, SEEK_END);
+ size_t size = ftell(inf);
+ rewind(inf);
+
+ char* addr = new char[size];
+ if (fread(addr, 1, size, inf) != size) {
+ delete[] addr;
+ fclose(inf);
+ return false;
+ }
+ fclose(inf);
+ UErrorCode err = U_ZERO_ERROR;
+ udata_setCommonData(reinterpret_cast<void*>(addr), &err);
+ return err == U_ZERO_ERROR;
+#endif
#endif
}
diff --git a/src/icu_util.h b/src/icu_util.h
index 478abce..6b50c18 100644
--- a/src/icu_util.h
+++ b/src/icu_util.h
@@ -35,7 +35,7 @@
// Call this function to load ICU's data tables for the current process. This
// function should be called before ICU is used.
-bool InitializeICU();
+bool InitializeICU(const char* icu_data_file);
} } // namespace v8::internal
diff --git a/src/json-parser.h b/src/json-parser.h
index 0973589..4c2b479 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -606,6 +606,7 @@
int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count));
Handle<StringType> seq_string =
NewRawString<StringType>(factory(), length, pretenure_);
+ ASSERT(!seq_string.is_null());
// Copy prefix into seq_str.
SinkChar* dest = seq_string->GetChars();
String::WriteToFlat(*prefix, dest, start, end);
@@ -793,6 +794,7 @@
} while (c0_ != '"');
int length = position_ - beg_pos;
Handle<String> result = factory()->NewRawOneByteString(length, pretenure_);
+ ASSERT(!result.is_null());
uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
String::WriteToFlat(*source_, dest, beg_pos, position_);
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index a75b3de..3926969 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -266,6 +266,7 @@
factory_->ToObject(factory_->empty_string()));
part_length_ = kInitialPartLength;
current_part_ = factory_->NewRawOneByteString(part_length_);
+ ASSERT(!current_part_.is_null());
tojson_string_ = factory_->toJSON_string();
stack_ = factory_->NewJSArray(8);
}
@@ -309,6 +310,7 @@
if (object->IsOneByteRepresentationUnderneath()) {
Handle<String> result =
isolate->factory()->NewRawOneByteString(worst_case_length);
+ ASSERT(!result.is_null());
DisallowHeapAllocation no_gc;
return StringifyString_<SeqOneByteString>(
isolate,
@@ -317,6 +319,7 @@
} else {
Handle<String> result =
isolate->factory()->NewRawTwoByteString(worst_case_length);
+ ASSERT(!result.is_null());
DisallowHeapAllocation no_gc;
return StringifyString_<SeqTwoByteString>(
isolate,
@@ -390,13 +393,16 @@
if (check.HasOverflowed()) return STACK_OVERFLOW;
int length = Smi::cast(stack_->length())->value();
- FixedArray* elements = FixedArray::cast(stack_->elements());
- for (int i = 0; i < length; i++) {
- if (elements->get(i) == *object) {
- return CIRCULAR;
+ {
+ DisallowHeapAllocation no_allocation;
+ FixedArray* elements = FixedArray::cast(stack_->elements());
+ for (int i = 0; i < length; i++) {
+ if (elements->get(i) == *object) {
+ return CIRCULAR;
+ }
}
}
- stack_->EnsureSize(length + 1);
+ JSArray::EnsureSize(stack_, length + 1);
FixedArray::cast(stack_->elements())->set(length, *object);
stack_->set_length(Smi::FromInt(length + 1));
return SUCCESS;
@@ -722,7 +728,6 @@
void BasicJsonStringifier::Accumulate() {
if (accumulator()->length() + current_part_->length() > String::kMaxLength) {
// Screw it. Simply set the flag and carry on. Throw exception at the end.
- // We most likely will trigger a real OOM before even reaching this point.
set_accumulator(factory_->empty_string());
overflowed_ = true;
} else {
@@ -741,6 +746,7 @@
} else {
current_part_ = factory_->NewRawTwoByteString(part_length_);
}
+ ASSERT(!current_part_.is_null());
current_index_ = 0;
}
@@ -749,6 +755,7 @@
ShrinkCurrentPart();
Accumulate();
current_part_ = factory_->NewRawTwoByteString(part_length_);
+ ASSERT(!current_part_.is_null());
current_index_ = 0;
is_ascii_ = false;
}
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 012c251..a30fc26 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -466,6 +466,7 @@
// Unable to compile regexp.
Handle<String> error_message =
isolate->factory()->NewStringFromUtf8(CStrVector(result.error_message));
+ ASSERT(!error_message.is_null());
CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate);
return false;
}
@@ -690,7 +691,8 @@
int32_t* match) {
ASSERT(last_match_info->HasFastObjectElements());
int capture_register_count = (capture_count + 1) * 2;
- last_match_info->EnsureSize(capture_register_count + kLastMatchOverhead);
+ JSArray::EnsureSize(last_match_info,
+ capture_register_count + kLastMatchOverhead);
DisallowHeapAllocation no_allocation;
FixedArray* array = FixedArray::cast(last_match_info->elements());
if (match != NULL) {
diff --git a/src/liveedit.cc b/src/liveedit.cc
index a812b75..5eae107 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -2013,8 +2013,8 @@
DropActivationsInActiveThread(shared_info_array, result, do_drop);
if (error_message != NULL) {
// Add error message as an array extra element.
- Vector<const char> vector_message(error_message, StrLength(error_message));
- Handle<String> str = isolate->factory()->NewStringFromAscii(vector_message);
+ Handle<String> str = isolate->factory()->NewStringFromAscii(
+ CStrVector(error_message));
SetElementSloppy(result, len, str);
}
return result;
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index b26ca6a..4eb178b 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -4086,6 +4086,7 @@
if (p->TryParallelSweeping()) {
SweepConservatively<SWEEP_IN_PARALLEL>(space, &private_free_list, p);
free_list->Concatenate(&private_free_list);
+ p->set_parallel_sweeping(MemoryChunk::PARALLEL_SWEEPING_FINALIZE);
}
}
}
@@ -4284,10 +4285,11 @@
PageIterator it(space);
while (it.has_next()) {
Page* p = it.next();
- if (p->parallel_sweeping() == MemoryChunk::PARALLEL_SWEEPING_IN_PROGRESS) {
+ if (p->parallel_sweeping() == MemoryChunk::PARALLEL_SWEEPING_FINALIZE) {
p->set_parallel_sweeping(MemoryChunk::PARALLEL_SWEEPING_DONE);
p->MarkSweptConservatively();
}
+ ASSERT(p->parallel_sweeping() == MemoryChunk::PARALLEL_SWEEPING_DONE);
}
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index b3f23e6..c358ee6 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1064,25 +1064,15 @@
// This was not always the case. This ASSERT is here to catch
// leftover incorrect uses.
ASSERT(AllowHeapAllocation::IsAllowed());
- CALL_HEAP_FUNCTION(isolate,
- object->GetElementWithReceiver(isolate, *object, index),
- Object);
+ return Object::GetElementWithReceiver(isolate, object, object, index);
}
-static Handle<Object> GetElementNoExceptionThrownHelper(Isolate* isolate,
- Handle<Object> object,
- uint32_t index) {
- CALL_HEAP_FUNCTION(isolate,
- object->GetElementWithReceiver(isolate, *object, index),
- Object);
-}
-
Handle<Object> Object::GetElementNoExceptionThrown(Isolate* isolate,
Handle<Object> object,
uint32_t index) {
Handle<Object> result =
- GetElementNoExceptionThrownHelper(isolate, object, index);
+ Object::GetElementWithReceiver(isolate, object, object, index);
CHECK_NOT_EMPTY_HANDLE(isolate, result);
return result;
}
@@ -6527,20 +6517,20 @@
}
-void JSArray::EnsureSize(int required_size) {
- ASSERT(HasFastSmiOrObjectElements());
- FixedArray* elts = FixedArray::cast(elements());
+void JSArray::EnsureSize(Handle<JSArray> array, int required_size) {
+ ASSERT(array->HasFastSmiOrObjectElements());
+ Handle<FixedArray> elts = handle(FixedArray::cast(array->elements()));
const int kArraySizeThatFitsComfortablyInNewSpace = 128;
if (elts->length() < required_size) {
// Doubling in size would be overkill, but leave some slack to avoid
// constantly growing.
- Expand(required_size + (required_size >> 3));
+ Expand(array, required_size + (required_size >> 3));
// It's a performance benefit to keep a frequently used array in new-space.
- } else if (!GetHeap()->new_space()->Contains(elts) &&
+ } else if (!array->GetHeap()->new_space()->Contains(*elts) &&
required_size < kArraySizeThatFitsComfortablyInNewSpace) {
// Expand will allocate a new backing store in new space even if the size
// we asked for isn't larger than what we had before.
- Expand(required_size);
+ Expand(array, required_size);
}
}
diff --git a/src/objects.cc b/src/objects.cc
index c764b33..11f53b9 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -962,63 +962,70 @@
}
-MaybeObject* Object::GetElementWithReceiver(Isolate* isolate,
- Object* receiver,
- uint32_t index) {
- Heap* heap = isolate->heap();
- Object* holder = this;
+Handle<Object> Object::GetElementWithReceiver(Isolate* isolate,
+ Handle<Object> object,
+ Handle<Object> receiver,
+ uint32_t index) {
+ Handle<Object> holder;
// Iterate up the prototype chain until an element is found or the null
// prototype is encountered.
- for (holder = this;
- holder != heap->null_value();
- holder = holder->GetPrototype(isolate)) {
+ for (holder = object;
+ !holder->IsNull();
+ holder = Handle<Object>(holder->GetPrototype(isolate), isolate)) {
if (!holder->IsJSObject()) {
Context* native_context = isolate->context()->native_context();
if (holder->IsNumber()) {
- holder = native_context->number_function()->instance_prototype();
+ holder = Handle<Object>(
+ native_context->number_function()->instance_prototype(), isolate);
} else if (holder->IsString()) {
- holder = native_context->string_function()->instance_prototype();
+ holder = Handle<Object>(
+ native_context->string_function()->instance_prototype(), isolate);
} else if (holder->IsSymbol()) {
- holder = native_context->symbol_function()->instance_prototype();
+ holder = Handle<Object>(
+ native_context->symbol_function()->instance_prototype(), isolate);
} else if (holder->IsBoolean()) {
- holder = native_context->boolean_function()->instance_prototype();
+ holder = Handle<Object>(
+ native_context->boolean_function()->instance_prototype(), isolate);
} else if (holder->IsJSProxy()) {
- return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
+ CALL_HEAP_FUNCTION(isolate,
+ Handle<JSProxy>::cast(holder)->GetElementWithHandler(
+ *receiver, index),
+ Object);
} else {
// Undefined and null have no indexed properties.
ASSERT(holder->IsUndefined() || holder->IsNull());
- return heap->undefined_value();
+ return isolate->factory()->undefined_value();
}
}
// Inline the case for JSObjects. Doing so significantly improves the
// performance of fetching elements where checking the prototype chain is
// necessary.
- JSObject* js_object = JSObject::cast(holder);
+ Handle<JSObject> js_object = Handle<JSObject>::cast(holder);
// Check access rights if needed.
if (js_object->IsAccessCheckNeeded()) {
- Isolate* isolate = heap->isolate();
- if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
- isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
- RETURN_IF_SCHEDULED_EXCEPTION(isolate);
- return heap->undefined_value();
+ if (!isolate->MayIndexedAccessWrapper(js_object, index, v8::ACCESS_GET)) {
+ isolate->ReportFailedAccessCheckWrapper(js_object, v8::ACCESS_GET);
+ RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ return isolate->factory()->undefined_value();
}
}
if (js_object->HasIndexedInterceptor()) {
- return js_object->GetElementWithInterceptor(receiver, index);
+ return JSObject::GetElementWithInterceptor(js_object, receiver, index);
}
- if (js_object->elements() != heap->empty_fixed_array()) {
- MaybeObject* result = js_object->GetElementsAccessor()->Get(
+ if (js_object->elements() != isolate->heap()->empty_fixed_array()) {
+ Handle<Object> result = js_object->GetElementsAccessor()->Get(
receiver, js_object, index);
- if (result != heap->the_hole_value()) return result;
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());
+ if (!result->IsTheHole()) return result;
}
}
- return heap->undefined_value();
+ return isolate->factory()->undefined_value();
}
@@ -11279,9 +11286,9 @@
}
-void JSArray::Expand(int required_size) {
- GetIsolate()->factory()->SetElementsCapacityAndLength(
- Handle<JSArray>(this), required_size, required_size);
+void JSArray::Expand(Handle<JSArray> array, int required_size) {
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ accessor->SetCapacityAndLength(array, required_size, required_size);
}
@@ -12922,46 +12929,41 @@
}
-MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
- uint32_t index) {
- Isolate* isolate = GetIsolate();
- HandleScope scope(isolate);
+Handle<Object> JSObject::GetElementWithInterceptor(Handle<JSObject> object,
+ Handle<Object> receiver,
+ uint32_t index) {
+ Isolate* isolate = object->GetIsolate();
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc(isolate);
- Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
- Handle<Object> this_handle(receiver, isolate);
- Handle<JSObject> holder_handle(this, isolate);
+ Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate);
if (!interceptor->getter()->IsUndefined()) {
v8::IndexedPropertyGetterCallback getter =
v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
LOG(isolate,
- ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
+ ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index));
PropertyCallbackArguments
- args(isolate, interceptor->data(), receiver, this);
+ args(isolate, interceptor->data(), *receiver, *object);
v8::Handle<v8::Value> result = args.Call(getter, index);
- RETURN_IF_SCHEDULED_EXCEPTION(isolate);
+ RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
if (!result.IsEmpty()) {
Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
result_internal->VerifyApiCallResultType();
- return *result_internal;
+ // Rebox handle before return.
+ return Handle<Object>(*result_internal, isolate);
}
}
- Heap* heap = holder_handle->GetHeap();
- ElementsAccessor* handler = holder_handle->GetElementsAccessor();
- MaybeObject* raw_result = handler->Get(*this_handle,
- *holder_handle,
- index);
- if (raw_result != heap->the_hole_value()) return raw_result;
+ ElementsAccessor* handler = object->GetElementsAccessor();
+ Handle<Object> result = handler->Get(receiver, object, index);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());
+ if (!result->IsTheHole()) return result;
- RETURN_IF_SCHEDULED_EXCEPTION(isolate);
-
- Object* pt = holder_handle->GetPrototype();
- if (pt == heap->null_value()) return heap->undefined_value();
- return pt->GetElementWithReceiver(isolate, *this_handle, index);
+ Handle<Object> proto(object->GetPrototype(), isolate);
+ if (proto->IsNull()) return isolate->factory()->undefined_value();
+ return Object::GetElementWithReceiver(isolate, proto, receiver, index);
}
diff --git a/src/objects.h b/src/objects.h
index c4d3f25..762892c 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1589,9 +1589,11 @@
Isolate* isolate,
Handle<Object> object,
uint32_t index);
- MUST_USE_RESULT MaybeObject* GetElementWithReceiver(Isolate* isolate,
- Object* receiver,
- uint32_t index);
+
+ static Handle<Object> GetElementWithReceiver(Isolate* isolate,
+ Handle<Object> object,
+ Handle<Object> receiver,
+ uint32_t index);
// Return the object's prototype (might be Heap::null_value()).
Object* GetPrototype(Isolate* isolate);
@@ -2480,8 +2482,9 @@
// Returns the index'th element.
// The undefined object if index is out of bounds.
- MUST_USE_RESULT MaybeObject* GetElementWithInterceptor(Object* receiver,
- uint32_t index);
+ static Handle<Object> GetElementWithInterceptor(Handle<JSObject> object,
+ Handle<Object> receiver,
+ uint32_t index);
enum SetFastElementsCapacitySmiMode {
kAllowSmiElements,
@@ -10028,9 +10031,15 @@
// Casting.
static inline JSArray* cast(Object* obj);
- // Uses handles. Ensures that the fixed array backing the JSArray has at
+ // Ensures that the fixed array backing the JSArray has at
// least the stated size.
- inline void EnsureSize(int minimum_size_of_backing_fixed_array);
+ static inline void EnsureSize(Handle<JSArray> array,
+ int minimum_size_of_backing_fixed_array);
+
+ // Expand the fixed array backing of a fast-case JSArray to at least
+ // the requested size.
+ static void Expand(Handle<JSArray> array,
+ int minimum_size_of_backing_fixed_array);
// Dispatched behavior.
DECLARE_PRINTER(JSArray)
@@ -10044,10 +10053,6 @@
static const int kSize = kLengthOffset + kPointerSize;
private:
- // Expand the fixed array backing of a fast-case JSArray to at least
- // the requested size.
- void Expand(int minimum_size_of_backing_fixed_array);
-
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArray);
};
diff --git a/src/parser.cc b/src/parser.cc
index 56eec54..c7ea634 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -215,6 +215,7 @@
Handle<String> result = symbol_cache_.at(symbol_id);
if (result.is_null()) {
result = scanner()->AllocateInternalizedString(isolate_);
+ ASSERT(!result.is_null());
symbol_cache_.at(symbol_id) = result;
return result;
}
@@ -615,6 +616,7 @@
Handle<FixedArray> elements = factory->NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
+ ASSERT(!arg_string.is_null());
elements->set(i, *arg_string);
}
Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
@@ -672,7 +674,10 @@
parser_->scanner()->LogSymbol(parser_->log_, parser_->position());
}
}
- return parser_->scanner()->AllocateInternalizedString(parser_->isolate_);
+ Handle<String> result =
+ parser_->scanner()->AllocateInternalizedString(parser_->isolate_);
+ ASSERT(!result.is_null());
+ return result;
}
@@ -1709,8 +1714,8 @@
return;
}
Handle<String> message_string =
- isolate()->factory()->NewStringFromUtf8(CStrVector("Variable"),
- TENURED);
+ isolate()->factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("Variable"));
Expression* expression =
NewThrowTypeError(isolate()->factory()->redeclaration_string(),
message_string, name);
@@ -3816,6 +3821,7 @@
RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
failed_ = true;
*error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
+ ASSERT(!error_->is_null());
// Zip to the end to make sure the no more input is read.
current_ = kEndMarker;
next_pos_ = in()->length();
diff --git a/src/runtime.cc b/src/runtime.cc
index 8d98f27..a5f6f26 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -3363,8 +3363,7 @@
array_builder_(heap->isolate(), estimated_part_count),
subject_(subject),
character_count_(0),
- is_ascii_(subject->IsOneByteRepresentation()),
- overflowed_(false) {
+ is_ascii_(subject->IsOneByteRepresentation()) {
// Require a non-zero initial size. Ensures that doubling the size to
// extend the array will work.
ASSERT(estimated_part_count > 0);
@@ -3412,11 +3411,6 @@
Handle<String> ToString() {
- if (overflowed_) {
- heap_->isolate()->ThrowInvalidStringLength();
- return Handle<String>();
- }
-
if (array_builder_.length() == 0) {
return heap_->isolate()->factory()->empty_string();
}
@@ -3424,6 +3418,7 @@
Handle<String> joined_string;
if (is_ascii_) {
Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_);
+ RETURN_IF_EMPTY_HANDLE_VALUE(heap_->isolate(), seq, Handle<String>());
DisallowHeapAllocation no_gc;
uint8_t* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_,
@@ -3434,6 +3429,7 @@
} else {
// Non-ASCII.
Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
+ RETURN_IF_EMPTY_HANDLE_VALUE(heap_->isolate(), seq, Handle<String>());
DisallowHeapAllocation no_gc;
uc16* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_,
@@ -3448,9 +3444,11 @@
void IncrementCharacterCount(int by) {
if (character_count_ > String::kMaxLength - by) {
- overflowed_ = true;
+ STATIC_ASSERT(String::kMaxLength < kMaxInt);
+ character_count_ = kMaxInt;
+ } else {
+ character_count_ += by;
}
- character_count_ += by;
}
private:
@@ -3475,7 +3473,6 @@
Handle<String> subject_;
int character_count_;
bool is_ascii_;
- bool overflowed_;
};
@@ -3932,22 +3929,25 @@
static_cast<int64_t>(pattern_len)) *
static_cast<int64_t>(matches) +
static_cast<int64_t>(subject_len);
- if (result_len_64 > INT_MAX) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+ int result_len;
+ if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) {
+ STATIC_ASSERT(String::kMaxLength < kMaxInt);
+ result_len = kMaxInt; // Provoke exception.
+ } else {
+ result_len = static_cast<int>(result_len_64);
}
- int result_len = static_cast<int>(result_len_64);
int subject_pos = 0;
int result_pos = 0;
- Handle<ResultSeqString> result;
+ Handle<String> result_seq;
if (ResultSeqString::kHasAsciiEncoding) {
- result = Handle<ResultSeqString>::cast(
- isolate->factory()->NewRawOneByteString(result_len));
+ result_seq = isolate->factory()->NewRawOneByteString(result_len);
} else {
- result = Handle<ResultSeqString>::cast(
- isolate->factory()->NewRawTwoByteString(result_len));
+ result_seq = isolate->factory()->NewRawTwoByteString(result_len);
}
+ RETURN_IF_EMPTY_HANDLE(isolate, result_seq);
+ Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(result_seq);
for (int i = 0; i < matches; i++) {
// Copy non-matched subject content.
@@ -4127,6 +4127,7 @@
answer = Handle<ResultSeqString>::cast(
isolate->factory()->NewRawTwoByteString(new_length));
}
+ ASSERT(!answer.is_null());
int prev = 0;
int position = 0;
@@ -6584,7 +6585,7 @@
if (s->IsOneByteRepresentationUnderneath()) {
Handle<SeqOneByteString> result =
isolate->factory()->NewRawOneByteString(length);
-
+ ASSERT(!result.is_null()); // Same length as input.
DisallowHeapAllocation no_gc;
String::FlatContent flat_content = s->GetFlatContent();
ASSERT(flat_content.IsFlat());
@@ -6604,6 +6605,8 @@
} else {
result = isolate->factory()->NewRawTwoByteString(length);
}
+ ASSERT(!result.is_null()); // Same length as input.
+
MaybeObject* maybe = ConvertCaseHelper(isolate, *s, *result, length, mapping);
Object* answer;
if (!maybe->ToObject(&answer)) return maybe;
@@ -6617,6 +6620,7 @@
if (length < 0) length = -length;
result = isolate->factory()->NewRawTwoByteString(length);
}
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
return ConvertCaseHelper(isolate, *s, *result, length, mapping);
}
@@ -7261,13 +7265,16 @@
String* element = String::cast(element_obj);
int increment = element->length();
if (increment > String::kMaxLength - length) {
- return isolate->ThrowInvalidStringLength();
+ STATIC_ASSERT(String::kMaxLength < kMaxInt);
+ length = kMaxInt; // Provoke exception;
+ break;
}
length += increment;
}
Handle<SeqTwoByteString> answer =
isolate->factory()->NewRawTwoByteString(length);
+ RETURN_IF_EMPTY_HANDLE(isolate, answer);
DisallowHeapAllocation no_gc;
@@ -8694,6 +8701,7 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) {
RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
+ RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
isolate->optimizing_compiler_thread()->Unblock();
return isolate->heap()->undefined_value();
}
@@ -9512,8 +9520,9 @@
CONVERT_SMI_ARG_CHECKED(message_id, 0);
const char* message = GetBailoutReason(
static_cast<BailoutReason>(message_id));
- Handle<Name> message_handle =
+ Handle<String> message_handle =
isolate->factory()->NewStringFromAscii(CStrVector(message));
+ RETURN_IF_EMPTY_HANDLE(isolate, message_handle);
return isolate->Throw(*message_handle);
}
@@ -11024,8 +11033,9 @@
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
RUNTIME_ASSERT(obj->HasIndexedInterceptor());
CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
-
- return obj->GetElementWithInterceptor(*obj, index);
+ Handle<Object> result = JSObject::GetElementWithInterceptor(obj, obj, index);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
@@ -11267,8 +11277,10 @@
VariableMode mode;
InitializationFlag init_flag;
locals->set(i * 2, *name);
- locals->set(i * 2 + 1, context->get(
- scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
+ int context_slot_index =
+ scope_info->ContextSlotIndex(*name, &mode, &init_flag);
+ Object* value = context->get(context_slot_index);
+ locals->set(i * 2 + 1, value);
}
}
diff --git a/src/spaces.h b/src/spaces.h
index 770b88a..05254d0 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -468,13 +468,16 @@
intptr_t GetFlags() { return flags_; }
- // PARALLEL_SWEEPING_PENDING - This page is ready for parallel sweeping.
- // PARALLEL_SWEEPING_IN_PROGRESS - This page is currently swept or was
- // swept by a sweeper thread.
// PARALLEL_SWEEPING_DONE - The page state when sweeping is complete or
// sweeping must not be performed on that page.
+ // PARALLEL_SWEEPING_FINALIZE - A sweeper thread is done sweeping this
+ // page and will not touch the page memory anymore.
+ // PARALLEL_SWEEPING_IN_PROGRESS - This page is currently swept by a
+ // sweeper thread.
+ // PARALLEL_SWEEPING_PENDING - This page is ready for parallel sweeping.
enum ParallelSweepingState {
PARALLEL_SWEEPING_DONE,
+ PARALLEL_SWEEPING_FINALIZE,
PARALLEL_SWEEPING_IN_PROGRESS,
PARALLEL_SWEEPING_PENDING
};
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 092eaa3..ff641dd 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -664,10 +664,14 @@
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
- JSObject* receiver = JSObject::cast(args[0]);
+ HandleScope scope(isolate);
+ Handle<JSObject> receiver = args.at<JSObject>(0);
ASSERT(args.smi_at(1) >= 0);
uint32_t index = args.smi_at(1);
- return receiver->GetElementWithInterceptor(receiver, index);
+ Handle<Object> result =
+ JSObject::GetElementWithInterceptor(receiver, receiver, index);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
diff --git a/src/uri.h b/src/uri.h
index 81ec0c5..1e73ddd 100644
--- a/src/uri.h
+++ b/src/uri.h
@@ -127,9 +127,11 @@
int dest_position = 0;
Handle<String> second_part;
+ ASSERT(unescaped_length <= String::kMaxLength);
if (one_byte) {
Handle<SeqOneByteString> dest =
isolate->factory()->NewRawOneByteString(unescaped_length);
+ ASSERT(!dest.is_null());
DisallowHeapAllocation no_allocation;
Vector<const Char> vector = GetCharVector<Char>(string);
for (int i = start_index; i < length; dest_position++) {
@@ -142,6 +144,7 @@
} else {
Handle<SeqTwoByteString> dest =
isolate->factory()->NewRawTwoByteString(unescaped_length);
+ ASSERT(!dest.is_null());
DisallowHeapAllocation no_allocation;
Vector<const Char> vector = GetCharVector<Char>(string);
for (int i = start_index; i < length; dest_position++) {
@@ -263,11 +266,7 @@
// We don't allow strings that are longer than a maximal length.
ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
- if (escaped_length > String::kMaxLength) {
- AllowHeapAllocation allocate_error_and_return;
- isolate->ThrowInvalidStringLength();
- return Handle<String>::null();
- }
+ if (escaped_length > String::kMaxLength) break; // Provoke exception.
}
}
@@ -276,6 +275,7 @@
Handle<SeqOneByteString> dest =
isolate->factory()->NewRawOneByteString(escaped_length);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, dest, Handle<String>());
int dest_position = 0;
{ DisallowHeapAllocation no_allocation;
diff --git a/src/version.cc b/src/version.cc
index 0374476..e606e70 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 25
-#define BUILD_NUMBER 24
-#define PATCH_LEVEL 1
+#define BUILD_NUMBER 25
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 182a35b..2f09743 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -74,6 +74,7 @@
'test-api/Threading2': [PASS, ['mode == debug', SLOW]],
'test-api/Threading3': [PASS, ['mode == debug', SLOW]],
'test-api/Threading4': [PASS, ['mode == debug', SLOW]],
+ 'test-strings/StringOOM*': [PASS, ['mode == debug', SKIP]],
}], # ALWAYS
##############################################################################
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index 0f37c3e..6ff5200 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -1352,3 +1352,62 @@
CHECK_EQ(Min(upper, lower), test);
}
}
+
+
+class DummyResource: public v8::String::ExternalStringResource {
+ public:
+ virtual const uint16_t* data() const { return NULL; }
+ virtual size_t length() const { return 1 << 30; }
+};
+
+
+class DummyOneByteResource: public v8::String::ExternalOneByteStringResource {
+ public:
+ virtual const char* data() const { return NULL; }
+ virtual size_t length() const { return 1 << 30; }
+};
+
+
+TEST(InvalidExternalString) {
+ CcTest::InitializeVM();
+ LocalContext context;
+ Isolate* isolate = CcTest::i_isolate();
+ { HandleScope scope(isolate);
+ DummyOneByteResource r;
+ CHECK(isolate->factory()->NewExternalStringFromAscii(&r).is_null());
+ CHECK(isolate->has_pending_exception());
+ isolate->clear_pending_exception();
+ }
+
+ { HandleScope scope(isolate);
+ DummyResource r;
+ CHECK(isolate->factory()->NewExternalStringFromTwoByte(&r).is_null());
+ CHECK(isolate->has_pending_exception());
+ isolate->clear_pending_exception();
+ }
+}
+
+
+#define INVALID_STRING_TEST(FUN, TYPE) \
+ TEST(StringOOM##FUN) { \
+ CcTest::InitializeVM(); \
+ LocalContext context; \
+ Isolate* isolate = CcTest::i_isolate(); \
+ STATIC_ASSERT(String::kMaxLength < kMaxInt); \
+ static const int invalid = String::kMaxLength + 1; \
+ HandleScope scope(isolate); \
+ Vector<TYPE> dummy = Vector<TYPE>::New(invalid); \
+ CHECK(isolate->factory()->FUN(Vector<const TYPE>::cast(dummy)).is_null()); \
+ memset(dummy.start(), 0x20, dummy.length() * sizeof(TYPE)); \
+ CHECK(isolate->has_pending_exception()); \
+ isolate->clear_pending_exception(); \
+ dummy.Dispose(); \
+ }
+
+INVALID_STRING_TEST(NewStringFromAscii, char)
+INVALID_STRING_TEST(NewStringFromUtf8, char)
+INVALID_STRING_TEST(NewStringFromOneByte, uint8_t)
+INVALID_STRING_TEST(InternalizeOneByteString, uint8_t)
+INVALID_STRING_TEST(InternalizeUtf8String, char)
+
+#undef INVALID_STRING_TEST
diff --git a/test/mjsunit/compiler/store-elimination.js b/test/mjsunit/compiler/store-elimination.js
new file mode 100644
index 0000000..1806ed9
--- /dev/null
+++ b/test/mjsunit/compiler/store-elimination.js
@@ -0,0 +1,94 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --store-elimination
+
+// Test local elimination of unobservable stores.
+
+function B(x, y) {
+ this.x = x;
+ this.y = y;
+ return this;
+}
+
+function test_store_store() {
+ var a = new B(1, 2);
+ a.x = 3; // eliminatable.
+ a.x = 4;
+ return a.x;
+}
+
+function test_store_load_store1() {
+ var a = new B(6, 7);
+ a.x = 3; // eliminatable.
+ var r = a.y;
+ a.x = 4;
+ return r;
+}
+
+function test_store_load_store2() {
+ var a = new B(6, 8);
+ a.x = 3; // not eliminatable, unless next load is eliminated.
+ var r = a.x;
+ a.x = 4;
+ return r;
+}
+
+function test_store_call_store() {
+ var a = new B(2, 9);
+ a.x = 3; // not eliminatable.
+ killall();
+ a.x = 4;
+ return a.y;
+}
+
+function test_store_deopt_store() {
+ var a = new B(2, 1);
+ a.x = 3; // not eliminatable (implicit ValueOf following)
+ var c = a + 2;
+ a.x = 4;
+ return a.y;
+}
+
+function killall() {
+ try { } catch(e) { }
+}
+
+%NeverOptimizeFunction(killall);
+
+function test(x, f) {
+ assertEquals(x, f());
+ assertEquals(x, f());
+ %OptimizeFunctionOnNextCall(f);
+ assertEquals(x, f());
+}
+
+test(4, test_store_store);
+test(7, test_store_load_store1);
+test(3, test_store_load_store2);
+test(9, test_store_call_store);
+test(1, test_store_deopt_store);
diff --git a/test/mjsunit/regress/regress-356053.js b/test/mjsunit/regress/regress-356053.js
new file mode 100644
index 0000000..8f0dbdd
--- /dev/null
+++ b/test/mjsunit/regress/regress-356053.js
@@ -0,0 +1,9 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --noconcurrent-recompilation --expose-gc --allow-natives-syntax
+
+%SetFlags("--concurrent-recompilation --block-concurrent-recompilation");
+gc();
+try { %UnblockConcurrentRecompilation(); } catch (e) { }
diff --git a/test/mjsunit/string-oom-replace-global-regexp-with-string.js b/test/mjsunit/string-oom-replace-global-regexp-with-string.js
index a527ae6..2de0110 100644
--- a/test/mjsunit/string-oom-replace-global-regexp-with-string.js
+++ b/test/mjsunit/string-oom-replace-global-regexp-with-string.js
@@ -2,13 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+
+
var a = 'a';
for (var i = 0; i < 5; i++) a += a;
var b = 'b';
for (var i = 0; i < 23; i++) b += b;
-function replace() {
+function replace1() {
a.replace(/./g, b);
}
-assertThrows(replace, RangeError);
+assertThrows(replace1, RangeError);
+
+
+var a = 'a';
+for (var i = 0; i < 16; i++) a += a;
+
+function replace2() {
+ a.replace(/a/g, a);
+}
+
+assertThrows(replace2, RangeError);
diff --git a/tools/gcmole/gcmole.lua b/tools/gcmole/gcmole.lua
index aa93247..cd91a91 100644
--- a/tools/gcmole/gcmole.lua
+++ b/tools/gcmole/gcmole.lua
@@ -66,7 +66,7 @@
end
end
-local ARCHS = ARGS[1] and { ARGS[1] } or { 'ia32', 'arm', 'x64' }
+local ARCHS = ARGS[1] and { ARGS[1] } or { 'ia32', 'arm', 'x64', 'arm64' }
local io = require "io"
local os = require "os"
@@ -196,7 +196,9 @@
arm = config { triple = "i586-unknown-linux",
arch_define = "V8_TARGET_ARCH_ARM" },
x64 = config { triple = "x86_64-unknown-linux",
- arch_define = "V8_TARGET_ARCH_X64" }
+ arch_define = "V8_TARGET_ARCH_X64" },
+ arm64 = config { triple = "x86_64-unknown-linux",
+ arch_define = "V8_TARGET_ARCH_ARM64" },
}
-------------------------------------------------------------------------------
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 6f97def..52143e9 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -27,6 +27,7 @@
{
'variables': {
+ 'icu_use_data_file_flag%': 0,
'v8_code': 1,
'v8_random_seed%': 314159265,
},
@@ -420,6 +421,8 @@
'../../src/hydrogen-representation-changes.h',
'../../src/hydrogen-sce.cc',
'../../src/hydrogen-sce.h',
+ '../../src/hydrogen-store-elimination.cc',
+ '../../src/hydrogen-store-elimination.h',
'../../src/hydrogen-uint32-analysis.cc',
'../../src/hydrogen-uint32-analysis.h',
'../../src/i18n.cc',
@@ -1018,6 +1021,17 @@
'../../src/default-platform.h',
],
}],
+ ['icu_use_data_file_flag==1', {
+ 'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE'],
+ }, { # else icu_use_data_file_flag !=1
+ 'conditions': [
+ ['OS=="win"', {
+ 'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_SHARED'],
+ }, {
+ 'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC'],
+ }],
+ ],
+ }],
],
},
{
diff --git a/tools/lexer-shell.cc b/tools/lexer-shell.cc
index 8c7debc..e2e4a9c 100644
--- a/tools/lexer-shell.cc
+++ b/tools/lexer-shell.cc
@@ -68,6 +68,7 @@
Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(source_),
length / 2));
+ CHECK_NOT_EMPTY_HANDLE(isolate, result);
stream_ =
new GenericStringUtf16CharacterStream(result, 0, result->length());
break;
@@ -75,6 +76,7 @@
case LATIN1: {
Handle<String> result = isolate->factory()->NewStringFromOneByte(
Vector<const uint8_t>(source_, length));
+ CHECK_NOT_EMPTY_HANDLE(isolate, result);
stream_ =
new GenericStringUtf16CharacterStream(result, 0, result->length());
break;