summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2009-11-27 22:53:39 +0100
committerRyan Dahl <ry@tinyclouds.org>2009-11-27 22:53:39 +0100
commit4129305b7cdfb6df9695225e62714ab6e80fccd3 (patch)
tree58128679c37d62fad73eb68203f6dfd4acc7dd80
parentdc093ef833561cfa8d85fbd649f62d2045d4e61f (diff)
downloadnodejs-4129305b7cdfb6df9695225e62714ab6e80fccd3.tar.gz
nodejs-4129305b7cdfb6df9695225e62714ab6e80fccd3.tar.bz2
nodejs-4129305b7cdfb6df9695225e62714ab6e80fccd3.zip
Upgrade v8 to 2.0.2
-rw-r--r--deps/v8/ChangeLog15
-rw-r--r--deps/v8/src/allocation.h2
-rw-r--r--deps/v8/src/arm/codegen-arm.cc45
-rw-r--r--deps/v8/src/arm/codegen-arm.h2
-rw-r--r--deps/v8/src/builtins.cc6
-rw-r--r--deps/v8/src/codegen.cc4
-rw-r--r--deps/v8/src/flag-definitions.h2
-rw-r--r--deps/v8/src/heap.cc52
-rw-r--r--deps/v8/src/heap.h1
-rw-r--r--deps/v8/src/ia32/codegen-ia32.cc49
-rw-r--r--deps/v8/src/ia32/codegen-ia32.h2
-rw-r--r--deps/v8/src/log-inl.h2
-rw-r--r--deps/v8/src/log.cc49
-rw-r--r--deps/v8/src/log.h11
-rw-r--r--deps/v8/src/macros.py5
-rw-r--r--deps/v8/src/objects-inl.h15
-rw-r--r--deps/v8/src/objects.cc94
-rw-r--r--deps/v8/src/objects.h2
-rw-r--r--deps/v8/src/runtime.cc28
-rw-r--r--deps/v8/src/serialize.cc8
-rw-r--r--deps/v8/src/v8.cc2
-rw-r--r--deps/v8/src/version.cc2
-rw-r--r--deps/v8/src/x64/codegen-x64.cc42
-rw-r--r--deps/v8/src/x64/codegen-x64.h2
-rw-r--r--deps/v8/test/cctest/test-log.cc66
-rw-r--r--deps/v8/test/cctest/test-thread-termination.cc45
-rw-r--r--deps/v8/test/mjsunit/regress/regress-515.js40
-rw-r--r--deps/v8/tools/gyp/v8.gyp1
28 files changed, 553 insertions, 41 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index 668cd9a92..bf2c244b4 100644
--- a/deps/v8/ChangeLog
+++ b/deps/v8/ChangeLog
@@ -1,3 +1,18 @@
+2009-11-24: Version 2.0.2
+
+ Improved profiler support.
+
+ Fixed bug that broke compilation of d8 with readline support.
+
+
+2009-11-20: Version 2.0.1
+
+ Fixed crash bug in String.prototype.replace.
+
+ Reverted a change which caused Chromium interactive ui test
+ failures.
+
+
2009-11-18: Version 2.0.0
Added support for VFP on ARM.
diff --git a/deps/v8/src/allocation.h b/deps/v8/src/allocation.h
index 586c4fd0d..70a3a0388 100644
--- a/deps/v8/src/allocation.h
+++ b/deps/v8/src/allocation.h
@@ -124,7 +124,7 @@ static void DeleteArray(T* array) {
// and StrNDup uses new and calls the FatalProcessOutOfMemory handler
// if allocation fails.
char* StrDup(const char* str);
-char* StrNDup(const char* str, size_t n);
+char* StrNDup(const char* str, int n);
// Allocation policy for allocating in the C free store using malloc
diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc
index b08615e61..c62756d5a 100644
--- a/deps/v8/src/arm/codegen-arm.cc
+++ b/deps/v8/src/arm/codegen-arm.cc
@@ -3385,6 +3385,51 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+ // This generates a fast version of:
+ // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+ VirtualFrame::SpilledScope spilled_scope;
+ ASSERT(args->length() == 1);
+ LoadAndSpill(args->at(0));
+ frame_->EmitPop(r1);
+ __ tst(r1, Operand(kSmiTagMask));
+ false_target()->Branch(eq);
+
+ __ LoadRoot(ip, Heap::kNullValueRootIndex);
+ __ cmp(r1, ip);
+ true_target()->Branch(eq);
+
+ Register map_reg = r2;
+ __ ldr(map_reg, FieldMemOperand(r1, HeapObject::kMapOffset));
+ // Undetectable objects behave like undefined when tested with typeof.
+ __ ldrb(r1, FieldMemOperand(map_reg, Map::kBitFieldOffset));
+ __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
+ __ cmp(r1, Operand(1 << Map::kIsUndetectable));
+ false_target()->Branch(eq);
+
+ __ ldrb(r1, FieldMemOperand(map_reg, Map::kInstanceTypeOffset));
+ __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
+ false_target()->Branch(lt);
+ __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
+ cc_reg_ = le;
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+ // This generates a fast version of:
+ // (%_ClassOf(arg) === 'Function')
+ VirtualFrame::SpilledScope spilled_scope;
+ ASSERT(args->length() == 1);
+ LoadAndSpill(args->at(0));
+ frame_->EmitPop(r0);
+ __ tst(r0, Operand(kSmiTagMask));
+ false_target()->Branch(eq);
+ Register map_reg = r2;
+ __ CompareObjectType(r0, map_reg, r1, JS_FUNCTION_TYPE);
+ cc_reg_ = eq;
+}
+
+
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 0);
diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h
index 8cbf450f3..30a1ae572 100644
--- a/deps/v8/src/arm/codegen-arm.h
+++ b/deps/v8/src/arm/codegen-arm.h
@@ -334,6 +334,8 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
+ void GenerateIsObject(ZoneList<Expression*>* args);
+ void GenerateIsFunction(ZoneList<Expression*>* args);
// Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args);
diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc
index fa1b34e65..b66635c50 100644
--- a/deps/v8/src/builtins.cc
+++ b/deps/v8/src/builtins.cc
@@ -380,6 +380,9 @@ BUILTIN(HandleApiCall) {
{
// Leaving JavaScript.
VMState state(EXTERNAL);
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ state.set_external_callback(v8::ToCData<Address>(callback_obj));
+#endif
value = callback(new_args);
}
if (value.IsEmpty()) {
@@ -446,6 +449,9 @@ static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
{
// Leaving JavaScript.
VMState state(EXTERNAL);
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ state.set_external_callback(v8::ToCData<Address>(callback_obj));
+#endif
value = callback(new_args);
}
if (value.IsEmpty()) {
diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc
index 6917d459c..a6d5fb47f 100644
--- a/deps/v8/src/codegen.cc
+++ b/deps/v8/src/codegen.cc
@@ -343,7 +343,9 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateLog, "_Log"},
{&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
{&CodeGenerator::GenerateMathSin, "_Math_sin"},
- {&CodeGenerator::GenerateMathCos, "_Math_cos"}
+ {&CodeGenerator::GenerateMathCos, "_Math_cos"},
+ {&CodeGenerator::GenerateIsObject, "_IsObject"},
+ {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
};
diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h
index 975350353..8c9bb22dc 100644
--- a/deps/v8/src/flag-definitions.h
+++ b/deps/v8/src/flag-definitions.h
@@ -143,7 +143,7 @@ DEFINE_bool(debug_info, true, "add debug information to compiled functions")
DEFINE_bool(strict, false, "strict error checking")
DEFINE_int(min_preparse_length, 1024,
"minimum length for automatic enable preparsing")
-DEFINE_bool(fast_compiler, true,
+DEFINE_bool(fast_compiler, false,
"use the fast-mode compiler for some top-level code")
DEFINE_bool(trace_bailout, false,
"print reasons for failing to use fast compilation")
diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc
index 43886c144..06dc59cdd 100644
--- a/deps/v8/src/heap.cc
+++ b/deps/v8/src/heap.cc
@@ -1762,6 +1762,41 @@ Object* Heap::AllocateSharedFunctionInfo(Object* name) {
}
+// Returns true for a character in a range. Both limits are inclusive.
+static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
+ // This makes uses of the the unsigned wraparound.
+ return character - from <= to - from;
+}
+
+
+static inline Object* MakeOrFindTwoCharacterString(uint32_t c1, uint32_t c2) {
+ String* symbol;
+ // Numeric strings have a different hash algorithm not known by
+ // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
+ if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
+ Heap::symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
+ return symbol;
+ // Now we know the length is 2, we might as well make use of that fact
+ // when building the new string.
+ } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
+ ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
+ Object* result = Heap::AllocateRawAsciiString(2);
+ if (result->IsFailure()) return result;
+ char* dest = SeqAsciiString::cast(result)->GetChars();
+ dest[0] = c1;
+ dest[1] = c2;
+ return result;
+ } else {
+ Object* result = Heap::AllocateRawTwoByteString(2);
+ if (result->IsFailure()) return result;
+ uc16* dest = SeqTwoByteString::cast(result)->GetChars();
+ dest[0] = c1;
+ dest[1] = c2;
+ return result;
+ }
+}
+
+
Object* Heap::AllocateConsString(String* first, String* second) {
int first_length = first->length();
if (first_length == 0) {
@@ -1774,6 +1809,16 @@ Object* Heap::AllocateConsString(String* first, String* second) {
}
int length = first_length + second_length;
+
+ // Optimization for 2-byte strings often used as keys in a decompression
+ // dictionary. Check whether we already have the string in the symbol
+ // table to prevent creation of many unneccesary strings.
+ if (length == 2) {
+ unsigned c1 = first->Get(0);
+ unsigned c2 = second->Get(0);
+ return MakeOrFindTwoCharacterString(c1, c2);
+ }
+
bool is_ascii = first->IsAsciiRepresentation()
&& second->IsAsciiRepresentation();
@@ -1843,6 +1888,13 @@ Object* Heap::AllocateSubString(String* buffer,
if (length == 1) {
return Heap::LookupSingleCharacterStringFromCode(
buffer->Get(start));
+ } else if (length == 2) {
+ // Optimization for 2-byte strings often used as keys in a decompression
+ // dictionary. Check whether we already have the string in the symbol
+ // table to prevent creation of many unneccesary strings.
+ unsigned c1 = buffer->Get(start);
+ unsigned c2 = buffer->Get(start + 1);
+ return MakeOrFindTwoCharacterString(c1, c2);
}
// Make an attempt to flatten the buffer to reduce access time.
diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h
index 8c1bb1887..90d714c7f 100644
--- a/deps/v8/src/heap.h
+++ b/deps/v8/src/heap.h
@@ -631,6 +631,7 @@ class Heap : public AllStatic {
}
static Object* LookupSymbol(String* str);
static bool LookupSymbolIfExists(String* str, String** symbol);
+ static bool LookupTwoCharsSymbolIfExists(String* str, String** symbol);
// Compute the matching symbol map for a string if possible.
// NULL is returned if string is in new space or not flattened.
diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc
index 69a17cd9b..ac2a7a026 100644
--- a/deps/v8/src/ia32/codegen-ia32.cc
+++ b/deps/v8/src/ia32/codegen-ia32.cc
@@ -4870,6 +4870,55 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+ // This generates a fast version of:
+ // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+ ASSERT(args->length() == 1);
+ Load(args->at(0));
+ Result obj = frame_->Pop();
+ obj.ToRegister();
+
+ __ test(obj.reg(), Immediate(kSmiTagMask));
+ destination()->false_target()->Branch(zero);
+ __ cmp(obj.reg(), Factory::null_value());
+ destination()->true_target()->Branch(equal);
+
+ Result map = allocator()->Allocate();
+ ASSERT(map.is_valid());
+ __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+ // Undetectable objects behave like undefined when tested with typeof.
+ __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset));
+ __ test(map.reg(), Immediate(1 << Map::kIsUndetectable));
+ destination()->false_target()->Branch(not_zero);
+ __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+ __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset));
+ __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE);
+ destination()->false_target()->Branch(less);
+ __ cmp(map.reg(), LAST_JS_OBJECT_TYPE);
+ obj.Unuse();
+ map.Unuse();
+ destination()->Split(less_equal);
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+ // This generates a fast version of:
+ // (%_ClassOf(arg) === 'Function')
+ ASSERT(args->length() == 1);
+ Load(args->at(0));
+ Result obj = frame_->Pop();
+ obj.ToRegister();
+ __ test(obj.reg(), Immediate(kSmiTagMask));
+ destination()->false_target()->Branch(zero);
+ Result temp = allocator()->Allocate();
+ ASSERT(temp.is_valid());
+ __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, temp.reg());
+ obj.Unuse();
+ temp.Unuse();
+ destination()->Split(equal);
+}
+
+
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0);
diff --git a/deps/v8/src/ia32/codegen-ia32.h b/deps/v8/src/ia32/codegen-ia32.h
index 0e69a63d8..ebab3caa1 100644
--- a/deps/v8/src/ia32/codegen-ia32.h
+++ b/deps/v8/src/ia32/codegen-ia32.h
@@ -512,6 +512,8 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
+ void GenerateIsObject(ZoneList<Expression*>* args);
+ void GenerateIsFunction(ZoneList<Expression*>* args);
// Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args);
diff --git a/deps/v8/src/log-inl.h b/deps/v8/src/log-inl.h
index 1844d2bf7..1500252a5 100644
--- a/deps/v8/src/log-inl.h
+++ b/deps/v8/src/log-inl.h
@@ -55,7 +55,7 @@ inline const char* StateToString(StateTag state) {
}
}
-VMState::VMState(StateTag state) : disabled_(true) {
+VMState::VMState(StateTag state) : disabled_(true), external_callback_(NULL) {
if (!Logger::is_logging()) {
return;
}
diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc
index 9acb7f785..aec813d97 100644
--- a/deps/v8/src/log.cc
+++ b/deps/v8/src/log.cc
@@ -30,6 +30,7 @@
#include "v8.h"
#include "bootstrapper.h"
+#include "global-handles.h"
#include "log.h"
#include "macro-assembler.h"
#include "serialize.h"
@@ -154,12 +155,18 @@ void StackTracer::Trace(TickSample* sample) {
return;
}
+ int i = 0;
+ const Address callback = Logger::current_state_ != NULL ?
+ Logger::current_state_->external_callback() : NULL;
+ if (callback != NULL) {
+ sample->stack[i++] = callback;
+ }
+
SafeStackTraceFrameIterator it(
reinterpret_cast<Address>(sample->fp),
reinterpret_cast<Address>(sample->sp),
reinterpret_cast<Address>(sample->sp),
js_entry_sp);
- int i = 0;
while (!it.done() && i < TickSample::kMaxFramesCount) {
sample->stack[i++] = it.frame()->pc();
it.Advance();
@@ -673,6 +680,26 @@ class CompressionHelper {
#endif // ENABLE_LOGGING_AND_PROFILING
+void Logger::CallbackEvent(String* name, Address entry_point) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ if (!Log::IsEnabled() || !FLAG_log_code) return;
+ LogMessageBuilder msg;
+ msg.Append("%s,%s,",
+ log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]);
+ msg.AppendAddress(entry_point);
+ SmartPointer<char> str =
+ name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ msg.Append(",1,\"%s\"", *str);
+ if (FLAG_compress_log) {
+ ASSERT(compression_helper_ != NULL);
+ if (!compression_helper_->HandleMessage(&msg)) return;
+ }
+ msg.Append('\n');
+ msg.WriteToLogFile();
+#endif
+}
+
+
void Logger::CodeCreateEvent(LogEventsAndTags tag,
Code* code,
const char* comment) {
@@ -1191,11 +1218,25 @@ void Logger::LogCompiledFunctions() {
LOG(CodeCreateEvent(Logger::SCRIPT_TAG,
shared->code(), *script_name));
}
- continue;
+ } else {
+ LOG(CodeCreateEvent(
+ Logger::LAZY_COMPILE_TAG, shared->code(), *func_name));
}
+ } else if (shared->function_data()->IsFunctionTemplateInfo()) {
+ // API function.
+ FunctionTemplateInfo* fun_data =
+ FunctionTemplateInfo::cast(shared->function_data());
+ Object* raw_call_data = fun_data->call_code();
+ if (!raw_call_data->IsUndefined()) {
+ CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
+ Object* callback_obj = call_data->callback();
+ Address entry_point = v8::ToCData<Address>(callback_obj);
+ LOG(CallbackEvent(*func_name, entry_point));
+ }
+ } else {
+ LOG(CodeCreateEvent(
+ Logger::LAZY_COMPILE_TAG, shared->code(), *func_name));
}
- // If no script or script has no name.
- LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, shared->code(), *func_name));
}
DeleteArray(sfis);
diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h
index e7931ca42..f099f02b6 100644
--- a/deps/v8/src/log.h
+++ b/deps/v8/src/log.h
@@ -91,15 +91,20 @@ class CompressionHelper;
class VMState BASE_EMBEDDED {
#ifdef ENABLE_LOGGING_AND_PROFILING
public:
- inline explicit VMState(StateTag state);
+ inline VMState(StateTag state);
inline ~VMState();
StateTag state() { return state_; }
+ Address external_callback() { return external_callback_; }
+ void set_external_callback(Address external_callback) {
+ external_callback_ = external_callback;
+ }
private:
bool disabled_;
StateTag state_;
VMState* previous_;
+ Address external_callback_;
#else
public:
explicit VMState(StateTag state) {}
@@ -122,6 +127,7 @@ class VMState BASE_EMBEDDED {
V(CALL_MISS_TAG, "CallMiss", "cm") \
V(CALL_NORMAL_TAG, "CallNormal", "cn") \
V(CALL_PRE_MONOMORPHIC_TAG, "CallPreMonomorphic", "cpm") \
+ V(CALLBACK_TAG, "Callback", "cb") \
V(EVAL_TAG, "Eval", "e") \
V(FUNCTION_TAG, "Function", "f") \
V(KEYED_LOAD_IC_TAG, "KeyedLoadIC", "klic") \
@@ -200,6 +206,8 @@ class Logger {
// ==== Events logged by --log-code. ====
+ // Emits a code event for a callback function.
+ static void CallbackEvent(String* name, Address entry_point);
// Emits a code create event.
static void CodeCreateEvent(LogEventsAndTags tag,
Code* code, const char* source);
@@ -330,6 +338,7 @@ class Logger {
friend class TimeLog;
friend class Profiler;
friend class SlidingStateWindow;
+ friend class StackTracer;
friend class VMState;
friend class LoggerTestHelper;
diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py
index d6a2426c5..5b06099a8 100644
--- a/deps/v8/src/macros.py
+++ b/deps/v8/src/macros.py
@@ -79,11 +79,10 @@ macro IS_NULL_OR_UNDEFINED(arg) = (arg == null);
macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined');
macro IS_NUMBER(arg) = (typeof(arg) === 'number');
macro IS_STRING(arg) = (typeof(arg) === 'string');
-macro IS_OBJECT(arg) = (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp');
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
+macro IS_OBJECT(arg) = (%_IsObject(arg));
macro IS_ARRAY(arg) = (%_IsArray(arg));
-# IS_FUNCTION uses %_ClassOf rather than typeof so as to exclude regexps.
-macro IS_FUNCTION(arg) = (%_ClassOf(arg) === 'Function');
+macro IS_FUNCTION(arg) = (%_IsFunction(arg));
macro IS_REGEXP(arg) = (%_ClassOf(arg) === 'RegExp');
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h
index 507a3ab6b..7a6444de5 100644
--- a/deps/v8/src/objects-inl.h
+++ b/deps/v8/src/objects-inl.h
@@ -3103,8 +3103,19 @@ void Map::ClearCodeCache() {
void JSArray::EnsureSize(int required_size) {
ASSERT(HasFastElements());
- if (elements()->length() >= required_size) return;
- Expand(required_size);
+ Array* elts = 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));
+ // It's a performance benefit to keep a frequently used array in new-space.
+ } else if (!Heap::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);
+ }
}
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 5ccacb786..f37658551 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -1463,8 +1463,8 @@ Object* JSObject::SetPropertyPostInterceptor(String* name,
Object* JSObject::ReplaceSlowProperty(String* name,
- Object* value,
- PropertyAttributes attributes) {
+ Object* value,
+ PropertyAttributes attributes) {
StringDictionary* dictionary = property_dictionary();
int old_index = dictionary->FindEntry(name);
int new_enumeration_index = 0; // 0 means "Use the next available index."
@@ -1478,6 +1478,7 @@ Object* JSObject::ReplaceSlowProperty(String* name,
return SetNormalizedProperty(name, value, new_details);
}
+
Object* JSObject::ConvertDescriptorToFieldAndMapTransition(
String* name,
Object* new_value,
@@ -1869,6 +1870,14 @@ Object* JSObject::SetProperty(LookupResult* result,
// interceptor calls.
AssertNoContextChange ncc;
+ // Optimization for 2-byte strings often used as keys in a decompression
+ // dictionary. We make these short keys into symbols to avoid constantly
+ // reallocating them.
+ if (!name->IsSymbol() && name->length() <= 2) {
+ Object* symbol_version = Heap::LookupSymbol(name);
+ if (!symbol_version->IsFailure()) name = String::cast(symbol_version);
+ }
+
// Check access rights if needed.
if (IsAccessCheckNeeded()
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
@@ -5240,9 +5249,7 @@ void JSArray::Expand(int required_size) {
Handle<JSArray> self(this);
Handle<FixedArray> old_backing(FixedArray::cast(elements()));
int old_size = old_backing->length();
- // Doubling in size would be overkill, but leave some slack to avoid
- // constantly growing.
- int new_size = required_size + (required_size >> 3);
+ int new_size = required_size > old_size ? required_size : old_size;
Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size);
// Can't use this any more now because we may have had a GC!
for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
@@ -7327,6 +7334,67 @@ Object* SymbolTable::LookupString(String* string, Object** s) {
}
+// This class is used for looking up two character strings in the symbol table.
+// If we don't have a hit we don't want to waste much time so we unroll the
+// string hash calculation loop here for speed. Doesn't work if the two
+// characters form a decimal integer, since such strings have a different hash
+// algorithm.
+class TwoCharHashTableKey : public HashTableKey {
+ public:
+ TwoCharHashTableKey(uint32_t c1, uint32_t c2)
+ : c1_(c1), c2_(c2) {
+ // Char 1.
+ uint32_t hash = c1 + (c1 << 10);
+ hash ^= hash >> 6;
+ // Char 2.
+ hash += c2;
+ hash += hash << 10;
+ hash ^= hash >> 6;
+ // GetHash.
+ hash += hash << 3;
+ hash ^= hash >> 11;
+ hash += hash << 15;
+ if (hash == 0) hash = 27;
+#ifdef DEBUG
+ StringHasher hasher(2);
+ hasher.AddCharacter(c1);
+ hasher.AddCharacter(c2);
+ // If this assert fails then we failed to reproduce the two-character
+ // version of the string hashing algorithm above. One reason could be
+ // that we were passed two digits as characters, since the hash
+ // algorithm is different in that case.
+ ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
+#endif
+ hash_ = hash;
+ }
+
+ bool IsMatch(Object* o) {
+ if (!o->IsString()) return false;
+ String* other = String::cast(o);
+ if (other->length() != 2) return false;
+ if (other->Get(0) != c1_) return false;
+ return other->Get(1) == c2_;
+ }
+
+ uint32_t Hash() { return hash_; }
+ uint32_t HashForObject(Object* key) {
+ if (!key->IsString()) return 0;
+ return String::cast(key)->Hash();
+ }
+
+ Object* AsObject() {
+ // The TwoCharHashTableKey is only used for looking in the symbol
+ // table, not for adding to it.
+ UNREACHABLE();
+ return NULL;
+ }
+ private:
+ uint32_t c1_;
+ uint32_t c2_;
+ uint32_t hash_;
+};
+
+
bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
SymbolKey key(string);
int entry = FindEntry(&key);
@@ -7341,6 +7409,22 @@ bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
}
+bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
+ uint32_t c2,
+ String** symbol) {
+ TwoCharHashTableKey key(c1, c2);
+ int entry = FindEntry(&key);
+ if (entry == kNotFound) {
+ return false;
+ } else {
+ String* result = String::cast(KeyAt(entry));
+ ASSERT(StringShape(result).IsSymbol());
+ *symbol = result;
+ return true;
+ }
+}
+
+
Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
Utf8SymbolKey key(str);
return LookupKey(&key, s);
diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h
index 6ea0a820c..d22e7231f 100644
--- a/deps/v8/src/objects.h
+++ b/deps/v8/src/objects.h
@@ -2188,6 +2188,7 @@ class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> {
// true if it is found, assigning the symbol to the given output
// parameter.
bool LookupSymbolIfExists(String* str, String** symbol);
+ bool LookupTwoCharsSymbolIfExists(uint32_t c1, uint32_t c2, String** symbol);
// Casting.
static inline SymbolTable* cast(Object* obj);
@@ -3846,6 +3847,7 @@ class StringHasher {
bool is_array_index_;
bool is_first_char_;
bool is_valid_;
+ friend class TwoCharHashTableKey;
};
diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc
index ccb88851b..6ae22330a 100644
--- a/deps/v8/src/runtime.cc
+++ b/deps/v8/src/runtime.cc
@@ -1750,10 +1750,10 @@ static Object* StringReplaceRegExpWithString(String* subject,
// Index of end of last match.
int prev = 0;
- // Number of parts added by compiled replacement plus preceeding string
- // and possibly suffix after last match. It is possible for compiled
- // replacements to use two elements when encoded as two smis.
- const int parts_added_per_loop = compiled_replacement.parts() * 2 + 2;
+ // Number of parts added by compiled replacement plus preceeding
+ // 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());
@@ -2356,12 +2356,20 @@ static Object* Runtime_SubString(Arguments args) {
ASSERT(args.length() == 3);
CONVERT_CHECKED(String, value, args[0]);
- CONVERT_DOUBLE_CHECKED(from_number, args[1]);
- CONVERT_DOUBLE_CHECKED(to_number, args[2]);
-
- int start = FastD2I(from_number);
- int end = FastD2I(to_number);
-
+ Object* from = args[1];
+ Object* to = args[2];
+ int start, end;
+ // We have a fast integer-only case here to avoid a conversion to double in
+ // the common case where from and to are Smis.
+ if (from->IsSmi() && to->IsSmi()) {
+ start = Smi::cast(from)->value();
+ end = Smi::cast(to)->value();
+ } else {
+ CONVERT_DOUBLE_CHECKED(from_number, from);
+ CONVERT_DOUBLE_CHECKED(to_number, to);
+ start = FastD2I(from_number);
+ end = FastD2I(to_number);
+ }
RUNTIME_ASSERT(end >= start);
RUNTIME_ASSERT(start >= 0);
RUNTIME_ASSERT(end <= value->length());
diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc
index de87022e0..00cd69ec0 100644
--- a/deps/v8/src/serialize.cc
+++ b/deps/v8/src/serialize.cc
@@ -668,7 +668,7 @@ void Deserializer::ReadChunk(Object** current,
break;
case OBJECT_SERIALIZATION + CODE_SPACE:
ReadObject(CODE_SPACE, Heap::code_space(), current++);
- Logger::LogCodeObject(current[-1]);
+ LOG(LogCodeObject(current[-1]));
break;
case OBJECT_SERIALIZATION + CELL_SPACE:
ReadObject(CELL_SPACE, Heap::cell_space(), current++);
@@ -678,7 +678,7 @@ void Deserializer::ReadChunk(Object** current,
break;
case OBJECT_SERIALIZATION + kLargeCode:
ReadObject(kLargeCode, Heap::lo_space(), current++);
- Logger::LogCodeObject(current[-1]);
+ LOG(LogCodeObject(current[-1]));
break;
case OBJECT_SERIALIZATION + kLargeFixedArray:
ReadObject(kLargeFixedArray, Heap::lo_space(), current++);
@@ -687,7 +687,7 @@ void Deserializer::ReadChunk(Object** current,
Object* new_code_object = NULL;
ReadObject(kLargeCode, Heap::lo_space(), &new_code_object);
Code* code_object = reinterpret_cast<Code*>(new_code_object);
- Logger::LogCodeObject(code_object);
+ LOG(LogCodeObject(code_object));
// Setting a branch/call to another code object from code.
Address location_of_branch_data = reinterpret_cast<Address>(current);
Assembler::set_target_at(location_of_branch_data,
@@ -700,7 +700,7 @@ void Deserializer::ReadChunk(Object** current,
Object* new_code_object = NULL;
ReadObject(CODE_SPACE, Heap::code_space(), &new_code_object);
Code* code_object = reinterpret_cast<Code*>(new_code_object);
- Logger::LogCodeObject(code_object);
+ LOG(LogCodeObject(code_object));
// Setting a branch/call to another code object from code.
Address location_of_branch_data = reinterpret_cast<Address>(current);
Assembler::set_target_at(location_of_branch_data,
diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc
index d17274253..3bec827aa 100644
--- a/deps/v8/src/v8.cc
+++ b/deps/v8/src/v8.cc
@@ -116,7 +116,7 @@ bool V8::Initialize(Deserializer *des) {
if (FLAG_log_code) {
HandleScope scope;
- Logger::LogCompiledFunctions();
+ LOG(LogCompiledFunctions());
}
return true;
diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc
index b448032a6..f9dc9b75f 100644
--- a/deps/v8/src/version.cc
+++ b/deps/v8/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 0
-#define BUILD_NUMBER 0
+#define BUILD_NUMBER 2
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc
index e2296d9bd..b32357266 100644
--- a/deps/v8/src/x64/codegen-x64.cc
+++ b/deps/v8/src/x64/codegen-x64.cc
@@ -3616,6 +3616,48 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+ // This generates a fast version of:
+ // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+ ASSERT(args->length() == 1);
+ Load(args->at(0));
+ Result obj = frame_->Pop();
+ obj.ToRegister();
+ Condition is_smi = masm_->CheckSmi(obj.reg());
+ destination()->false_target()->Branch(is_smi);
+
+ __ Move(kScratchRegister, Factory::null_value());
+ __ cmpq(obj.reg(), kScratchRegister);
+ destination()->true_target()->Branch(equal);
+
+ __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset));
+ // Undetectable objects behave like undefined when tested with typeof.
+ __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ destination()->false_target()->Branch(not_zero);
+ __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE);
+ destination()->false_target()->Branch(less);
+ __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
+ obj.Unuse();
+ destination()->Split(less_equal);
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+ // This generates a fast version of:
+ // (%_ClassOf(arg) === 'Function')
+ ASSERT(args->length() == 1);
+ Load(args->at(0));
+ Result obj = frame_->Pop();
+ obj.ToRegister();
+ Condition is_smi = masm_->CheckSmi(obj.reg());
+ destination()->false_target()->Branch(is_smi);
+ __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, kScratchRegister);
+ obj.Unuse();
+ destination()->Split(equal);
+}
+
+
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0);
diff --git a/deps/v8/src/x64/codegen-x64.h b/deps/v8/src/x64/codegen-x64.h
index 0301daf3d..20df41a50 100644
--- a/deps/v8/src/x64/codegen-x64.h
+++ b/deps/v8/src/x64/codegen-x64.h
@@ -510,6 +510,8 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
+ void GenerateIsObject(ZoneList<Expression*>* args);
+ void GenerateIsFunction(ZoneList<Expression*>* args);
// Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args);
diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc
index 57004d7c8..de29fe097 100644
--- a/deps/v8/test/cctest/test-log.cc
+++ b/deps/v8/test/cctest/test-log.cc
@@ -247,7 +247,7 @@ TEST(ProfLazyMode) {
i::FLAG_logfile = "*";
// If tests are being run manually, V8 will be already initialized
- // by the test below.
+ // by the bottom test.
const bool need_to_set_up_logger = i::V8::IsRunning();
v8::HandleScope scope;
v8::Handle<v8::Context> env = v8::Context::New();
@@ -474,6 +474,70 @@ TEST(Issue23768) {
}
+static v8::Handle<v8::Value> ObjMethod1(const v8::Arguments& args) {
+ return v8::Handle<v8::Value>();
+}
+
+TEST(LogCallbacks) {
+ const bool saved_prof_lazy = i::FLAG_prof_lazy;
+ const bool saved_prof = i::FLAG_prof;
+ const bool saved_prof_auto = i::FLAG_prof_auto;
+ i::FLAG_prof = true;
+ i::FLAG_prof_lazy = false;
+ i::FLAG_prof_auto = false;
+ i::FLAG_logfile = "*";
+
+ // If tests are being run manually, V8 will be already initialized
+ // by the bottom test.
+ const bool need_to_set_up_logger = i::V8::IsRunning();
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ if (need_to_set_up_logger) Logger::Setup();
+ env->Enter();
+
+ // Skip all initially logged stuff.
+ EmbeddedVector<char, 102400> buffer;
+ int log_pos = GetLogLines(0, &buffer);
+
+ v8::Persistent<v8::FunctionTemplate> obj =
+ v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
+ obj->SetClassName(v8::String::New("Obj"));
+ v8::Handle<v8::ObjectTemplate> proto = obj->PrototypeTemplate();
+ v8::Local<v8::Signature> signature = v8::Signature::New(obj);
+ proto->Set(v8::String::New("method1"),
+ v8::FunctionTemplate::New(ObjMethod1,
+ v8::Handle<v8::Value>(),
+ signature),
+ static_cast<v8::PropertyAttribute>(v8::DontDelete));
+
+ env->Global()->Set(v8_str("Obj"), obj->GetFunction());
+ CompileAndRunScript("Obj.prototype.method1.toString();");
+
+ i::Logger::LogCompiledFunctions();
+ log_pos = GetLogLines(log_pos, &buffer);
+ CHECK_GT(log_pos, 0);
+ buffer[log_pos] = 0;
+
+ const char* callback_rec = "code-creation,Callback,";
+ char* pos = strstr(buffer.start(), callback_rec);
+ CHECK_NE(NULL, pos);
+ pos += strlen(callback_rec);
+ EmbeddedVector<char, 100> ref_data;
+ i::OS::SNPrintF(ref_data,
+ "0x%" V8PRIxPTR ",1,\"method1\"", ObjMethod1);
+ *(pos + strlen(ref_data.start())) = '\0';
+ CHECK_EQ(ref_data.start(), pos);
+
+ obj.Dispose();
+
+ env->Exit();
+ Logger::TearDown();
+ i::FLAG_prof_lazy = saved_prof_lazy;
+ i::FLAG_prof = saved_prof;
+ i::FLAG_prof_auto = saved_prof_auto;
+}
+
+
static inline bool IsStringEqualTo(const char* r, const char* s) {
return strncmp(r, s, strlen(r)) == 0;
}
diff --git a/deps/v8/test/cctest/test-thread-termination.cc b/deps/v8/test/cctest/test-thread-termination.cc
index 552f49df1..1e8102ec7 100644
--- a/deps/v8/test/cctest/test-thread-termination.cc
+++ b/deps/v8/test/cctest/test-thread-termination.cc
@@ -82,14 +82,30 @@ v8::Handle<v8::Value> DoLoop(const v8::Arguments& args) {
}
+v8::Handle<v8::Value> DoLoopNoCall(const v8::Arguments& args) {
+ v8::TryCatch try_catch;
+ v8::Script::Compile(v8::String::New("var term = true;"
+ "while(true) {"
+ " if (term) terminate();"
+ " term = false;"
+ "}"))->Run();
+ CHECK(try_catch.HasCaught());
+ CHECK(try_catch.Exception()->IsNull());
+ CHECK(try_catch.Message().IsEmpty());
+ CHECK(!try_catch.CanContinue());
+ return v8::Undefined();
+}
+
+
v8::Handle<v8::ObjectTemplate> CreateGlobalTemplate(
- v8::InvocationCallback terminate) {
+ v8::InvocationCallback terminate,
+ v8::InvocationCallback doloop) {
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
global->Set(v8::String::New("terminate"),
v8::FunctionTemplate::New(terminate));
global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail));
global->Set(v8::String::New("loop"), v8::FunctionTemplate::New(Loop));
- global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(DoLoop));
+ global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(doloop));
return global;
}
@@ -99,7 +115,25 @@ v8::Handle<v8::ObjectTemplate> CreateGlobalTemplate(
TEST(TerminateOnlyV8ThreadFromThreadItself) {
v8::HandleScope scope;
v8::Handle<v8::ObjectTemplate> global =
- CreateGlobalTemplate(TerminateCurrentThread);
+ CreateGlobalTemplate(TerminateCurrentThread, DoLoop);
+ v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
+ v8::Context::Scope context_scope(context);
+ // Run a loop that will be infinite if thread termination does not work.
+ v8::Handle<v8::String> source =
+ v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
+ v8::Script::Compile(source)->Run();
+ // Test that we can run the code again after thread termination.
+ v8::Script::Compile(source)->Run();
+ context.Dispose();
+}
+
+
+// Test that a single thread of JavaScript execution can terminate
+// itself in a loop that performs no calls.
+TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> global =
+ CreateGlobalTemplate(TerminateCurrentThread, DoLoopNoCall);
v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
v8::Context::Scope context_scope(context);
// Run a loop that will be infinite if thread termination does not work.
@@ -128,7 +162,7 @@ TEST(TerminateOnlyV8ThreadFromOtherThread) {
thread.Start();
v8::HandleScope scope;
- v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(Signal);
+ v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(Signal, DoLoop);
v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
v8::Context::Scope context_scope(context);
// Run a loop that will be infinite if thread termination does not work.
@@ -149,7 +183,8 @@ class LoopingThread : public v8::internal::Thread {
v8::Locker locker;
v8::HandleScope scope;
v8_thread_id_ = v8::V8::GetCurrentThreadId();
- v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(Signal);
+ v8::Handle<v8::ObjectTemplate> global =
+ CreateGlobalTemplate(Signal, DoLoop);
v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
v8::Context::Scope context_scope(context);
// Run a loop that will be infinite if thread termination does not work.
diff --git a/deps/v8/test/mjsunit/regress/regress-515.js b/deps/v8/test/mjsunit/regress/regress-515.js
new file mode 100644
index 000000000..7675fe19e
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-515.js
@@ -0,0 +1,40 @@
+// Copyright 2009 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.
+
+// Regression test for http://code.google.com/p/v8/issues/detail?id=515.
+//
+// The test passes if it does not crash.
+
+var length = 2048;
+var s = "";
+for (var i = 0; i < 2048; i++) {
+ s += '.';
+}
+
+var string = s + 'x' + s + 'x' + s;
+
+string.replace(/x/g, "")
diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp
index 75464f206..d7ee73f6e 100644
--- a/deps/v8/tools/gyp/v8.gyp
+++ b/deps/v8/tools/gyp/v8.gyp
@@ -81,6 +81,7 @@
['OS=="linux"', {
'cflags!': [
'-O2',
+ '-Os',
],
'cflags': [
'-fomit-frame-pointer',