Push version 2.4.2 to trunk.
Fixed GC crash bug.
Fixed stack corruption bug.
Fixed compilation for newer C++ compilers that found Operand(0) ambiguous.
git-svn-id: http://v8.googlecode.com/svn/trunk@5425 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index cdf1b0f..95a3640 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,41 +1,51 @@
+2010-09-08: Version 2.4.2
+
+ Fixed GC crash bug.
+
+ Fixed stack corruption bug.
+
+ Fixed compilation for newer C++ compilers that found Operand(0)
+ ambiguous.
+
+
2010-09-06: Version 2.4.1
- Added the ability for an embedding application to receive a callback
- when V8 allocates (V8::AddMemoryAllocationCallback) or deallocates
- (V8::RemoveMemoryAllocationCallback) from the OS.
+ Added the ability for an embedding application to receive a callback
+ when V8 allocates (V8::AddMemoryAllocationCallback) or deallocates
+ (V8::RemoveMemoryAllocationCallback) from the OS.
- Fixed several JSON bugs (including issue 855).
+ Fixed several JSON bugs (including issue 855).
- Fixed memory overrun crash bug triggered during V8's tick-based
- profiling.
+ Fixed memory overrun crash bug triggered during V8's tick-based
+ profiling.
- Performance improvements on all platforms.
+ Performance improvements on all platforms.
2010-09-01: Version 2.4.0
- Fix bug in Object.freeze and Object.seal when Array.prototype or
- Object.prototype is changed (issue 842).
+ Fix bug in Object.freeze and Object.seal when Array.prototype or
+ Object.prototype is changed (issue 842).
- Update Array.splice to follow Safari and Firefox when called
- with zero arguments.
+ Update Array.splice to follow Safari and Firefox when called
+ with zero arguments.
- Fix a missing live register when breaking at keyed loads on ARM.
+ Fix a missing live register when breaking at keyed loads on ARM.
- Performance improvements on all platforms.
+ Performance improvements on all platforms.
2010-08-25: Version 2.3.11
- Fix bug in RegExp related to copy-on-write arrays.
+ Fix bug in RegExp related to copy-on-write arrays.
- Refactoring of tools/test.py script, including the introduction of
- VARIANT_FLAGS that allows specification of sets of flags with which
- all tests should be run.
+ Refactoring of tools/test.py script, including the introduction of
+ VARIANT_FLAGS that allows specification of sets of flags with which
+ all tests should be run.
- Fix a bug in the handling of debug breaks in CallIC.
+ Fix a bug in the handling of debug breaks in CallIC.
- Performance improvements on all platforms.
+ Performance improvements on all platforms.
2010-08-23: Version 2.3.10
diff --git a/src/api.cc b/src/api.cc
index 4710557..0d01fcc 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1136,13 +1136,18 @@
ScriptData* ScriptData::New(const char* data, int length) {
// Return an empty ScriptData if the length is obviously invalid.
if (length % sizeof(unsigned) != 0) {
- return new i::ScriptDataImpl(i::Vector<unsigned>());
+ return new i::ScriptDataImpl();
}
// Copy the data to ensure it is properly aligned.
int deserialized_data_length = length / sizeof(unsigned);
+ // If aligned, don't create a copy of the data.
+ if (reinterpret_cast<intptr_t>(data) % sizeof(unsigned) == 0) {
+ return new i::ScriptDataImpl(data, length);
+ }
+ // Copy the data to align it.
unsigned* deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
- memcpy(deserialized_data, data, length);
+ i::MemCopy(deserialized_data, data, length);
return new i::ScriptDataImpl(
i::Vector<unsigned>(deserialized_data, deserialized_data_length));
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index a902fc2..8b21558 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -125,7 +125,7 @@
__ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
__ str(scratch1, FieldMemOperand(result, JSArray::kPropertiesOffset));
// Field JSArray::kElementsOffset is initialized later.
- __ mov(scratch3, Operand(0));
+ __ mov(scratch3, Operand(0, RelocInfo::NONE));
__ str(scratch3, FieldMemOperand(result, JSArray::kLengthOffset));
// Calculate the location of the elements array and set elements array member
@@ -311,7 +311,7 @@
Label argc_one_or_more, argc_two_or_more;
// Check for array construction with zero arguments or one.
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
__ b(ne, &argc_one_or_more);
// Handle construction of an empty array.
@@ -513,7 +513,7 @@
// r1: called object
__ bind(&non_function_call);
// Set expected number of arguments to zero (not changing r0).
- __ mov(r2, Operand(0));
+ __ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
@@ -843,7 +843,7 @@
// r5-r7, cp may be clobbered
// Clear the context before we push it when entering the JS frame.
- __ mov(cp, Operand(0));
+ __ mov(cp, Operand(0, RelocInfo::NONE));
// Enter an internal frame.
__ EnterInternalFrame();
@@ -1030,7 +1030,7 @@
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
__ str(r1, MemOperand(r2, -kPointerSize));
// Clear r1 to indicate a non-function being called.
- __ mov(r1, Operand(0));
+ __ mov(r1, Operand(0, RelocInfo::NONE));
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@@ -1060,7 +1060,8 @@
{ Label function;
__ tst(r1, r1);
__ b(ne, &function);
- __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
+ // Expected number of arguments is 0 for CALL_NON_FUNCTION.
+ __ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
@@ -1123,7 +1124,7 @@
// Push current limit and index.
__ bind(&okay);
__ push(r0); // limit
- __ mov(r1, Operand(0)); // initial index
+ __ mov(r1, Operand(0, RelocInfo::NONE)); // initial index
__ push(r1);
// Change context eagerly to get the right global object if necessary.
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 0e479e2..fa93030 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -296,7 +296,7 @@
STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
__ and_(exponent, source_, Operand(HeapNumber::kSignMask), SetCC);
// Subtract from 0 if source was negative.
- __ rsb(source_, source_, Operand(0), LeaveCC, ne);
+ __ rsb(source_, source_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
// We have -1, 0 or 1, which we treat specially. Register source_ contains
// absolute value: it is either equal to 1 (special case of -1 and 1),
@@ -309,7 +309,7 @@
HeapNumber::kExponentBias << HeapNumber::kExponentShift;
__ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq);
// 1, 0 and -1 all have 0 for the second word.
- __ mov(mantissa, Operand(0));
+ __ mov(mantissa, Operand(0, RelocInfo::NONE));
__ Ret();
__ bind(¬_special);
@@ -357,7 +357,7 @@
// Set the sign bit in scratch_ if the value was negative.
__ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs);
// Subtract from 0 if the value was negative.
- __ rsb(the_int_, the_int_, Operand(0), LeaveCC, cs);
+ __ rsb(the_int_, the_int_, Operand(0, RelocInfo::NONE), LeaveCC, cs);
// We should be masking the implict first digit of the mantissa away here,
// but it just ends up combining harmlessly with the last digit of the
// exponent that happens to be 1. The sign bit is 0 so we shift 10 to get
@@ -380,7 +380,7 @@
non_smi_exponent += 1 << HeapNumber::kExponentShift;
__ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent));
__ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset));
- __ mov(ip, Operand(0));
+ __ mov(ip, Operand(0, RelocInfo::NONE));
__ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
__ Ret();
}
@@ -604,7 +604,7 @@
Operand(lhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord),
SetCC);
__ b(ne, &one_is_nan);
- __ cmp(lhs_mantissa, Operand(0));
+ __ cmp(lhs_mantissa, Operand(0, RelocInfo::NONE));
__ b(ne, &one_is_nan);
__ bind(lhs_not_nan);
@@ -619,7 +619,7 @@
Operand(rhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord),
SetCC);
__ b(ne, &one_is_nan);
- __ cmp(rhs_mantissa, Operand(0));
+ __ cmp(rhs_mantissa, Operand(0, RelocInfo::NONE));
__ b(eq, &neither_is_nan);
__ bind(&one_is_nan);
@@ -1085,8 +1085,8 @@
// "tos_" is a register, and contains a non zero value by default.
// Hence we only need to overwrite "tos_" with zero to return false for
// FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
- __ mov(tos_, Operand(0), LeaveCC, eq); // for FP_ZERO
- __ mov(tos_, Operand(0), LeaveCC, vs); // for FP_NAN
+ __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); // for FP_ZERO
+ __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN
__ Ret();
__ bind(¬_heap_number);
@@ -1131,7 +1131,7 @@
// Return 0 in "tos_" for false .
__ bind(&false_result);
- __ mov(tos_, Operand(0));
+ __ mov(tos_, Operand(0, RelocInfo::NONE));
__ Ret();
}
@@ -2231,7 +2231,7 @@
__ ldr(r0, MemOperand(r0, type_ * sizeof(TranscendentalCache::caches_[0])));
// r0 points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
__ b(eq, &runtime_call);
#ifdef DEBUG
@@ -2311,12 +2311,12 @@
// smi while we are at it.
__ bic(ip, r0, Operand(0x80000000), SetCC);
__ b(eq, &slow);
- __ rsb(r0, r0, Operand(0));
+ __ rsb(r0, r0, Operand(0, RelocInfo::NONE));
__ StubReturn(1);
} else {
// The value of the expression is a smi and 0 is OK for -0. Try
// optimistic subtraction '0 - value'.
- __ rsb(r0, r0, Operand(0), SetCC);
+ __ rsb(r0, r0, Operand(0, RelocInfo::NONE), SetCC);
__ StubReturn(1, vc);
// We don't have to reverse the optimistic neg since the only case
// where we fall through is the minimum negative Smi, which is the case
@@ -2429,9 +2429,9 @@
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of a
// JS entry frame.
- __ cmp(fp, Operand(0));
+ __ cmp(fp, Operand(0, RelocInfo::NONE));
// Set cp to NULL if fp is NULL.
- __ mov(cp, Operand(0), LeaveCC, eq);
+ __ mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq);
// Restore cp otherwise.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG
@@ -2497,9 +2497,9 @@
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of a
// JS entry frame.
- __ cmp(fp, Operand(0));
+ __ cmp(fp, Operand(0, RelocInfo::NONE));
// Set cp to NULL if fp is NULL.
- __ mov(cp, Operand(0), LeaveCC, eq);
+ __ mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq);
// Restore cp otherwise.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG
@@ -2567,7 +2567,7 @@
(frame_alignment_skew + kPointerSize) & frame_alignment_mask;
if (alignment_before_call > 0) {
// Push until the alignment before the call is met.
- __ mov(r2, Operand(0));
+ __ mov(r2, Operand(0, RelocInfo::NONE));
for (int i = alignment_before_call;
(i & frame_alignment_mask) != 0;
i += kPointerSize) {
@@ -2991,7 +2991,7 @@
// of the arguments object and the elements array in words.
Label add_arguments_object;
__ bind(&try_allocate);
- __ cmp(r1, Operand(0));
+ __ cmp(r1, Operand(0, RelocInfo::NONE));
__ b(eq, &add_arguments_object);
__ mov(r1, Operand(r1, LSR, kSmiTagSize));
__ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize));
@@ -3028,7 +3028,7 @@
// If there are no actual arguments, we're done.
Label done;
- __ cmp(r1, Operand(0));
+ __ cmp(r1, Operand(0, RelocInfo::NONE));
__ b(eq, &done);
// Get the parameters pointer from the stack.
@@ -3054,7 +3054,7 @@
// Post-increment r4 with kPointerSize on each iteration.
__ str(r3, MemOperand(r4, kPointerSize, PostIndex));
__ sub(r1, r1, Operand(1));
- __ cmp(r1, Operand(0));
+ __ cmp(r1, Operand(0, RelocInfo::NONE));
__ b(ne, &loop);
// Return and remove the on-stack parameters.
@@ -3452,7 +3452,7 @@
// of the original receiver from the call site).
__ str(r1, MemOperand(sp, argc_ * kPointerSize));
__ mov(r0, Operand(argc_)); // Setup the number of arguments.
- __ mov(r2, Operand(0));
+ __ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
@@ -3794,7 +3794,7 @@
if (!ascii) {
__ add(count, count, Operand(count), SetCC);
} else {
- __ cmp(count, Operand(0));
+ __ cmp(count, Operand(0, RelocInfo::NONE));
}
__ b(eq, &done);
@@ -3849,7 +3849,7 @@
if (!ascii) {
__ add(count, count, Operand(count), SetCC);
} else {
- __ cmp(count, Operand(0));
+ __ cmp(count, Operand(0, RelocInfo::NONE));
}
__ b(eq, &done);
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 698d0c8..f985fb4 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -770,7 +770,7 @@
ToBooleanStub stub(tos);
frame_->CallStub(&stub, 0);
// Convert the result in "tos" to a condition code.
- __ cmp(tos, Operand(0));
+ __ cmp(tos, Operand(0, RelocInfo::NONE));
} else {
// Implements slow case by calling the runtime.
frame_->EmitPush(tos);
@@ -1129,7 +1129,7 @@
__ mov(int32, Operand(int32, LSR, shift_value), SetCC);
} else {
// SHR is special because it is required to produce a positive answer.
- __ cmp(int32, Operand(0));
+ __ cmp(int32, Operand(0, RelocInfo::NONE));
}
if (CpuFeatures::IsSupported(VFP3)) {
__ b(mi, &result_not_a_smi);
@@ -1513,7 +1513,7 @@
}
__ mov(tos, Operand(tos, LSL, kSmiTagSize));
} else {
- __ cmp(tos, Operand(0));
+ __ cmp(tos, Operand(0, RelocInfo::NONE));
deferred->JumpToAnswerOutOfRange(mi);
}
break;
@@ -1653,7 +1653,7 @@
// We call with 0 args because there are 0 on the stack.
CompareStub stub(cc, strict, kBothCouldBeNaN, true, lhs, rhs);
frame_->CallStub(&stub, 0);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
exit.Jump();
smi.Bind();
@@ -1817,7 +1817,7 @@
// frame.
Label loop;
// r3 is a small non-negative integer, due to the test above.
- __ cmp(r3, Operand(0));
+ __ cmp(r3, Operand(0, RelocInfo::NONE));
__ b(eq, &invoke);
// Compute the address of the first argument.
__ add(r2, r2, Operand(r3, LSL, kPointerSizeLog2));
@@ -1975,7 +1975,7 @@
} else if (node->fun() != NULL) {
Load(node->fun());
} else {
- frame_->EmitPush(Operand(0));
+ frame_->EmitPush(Operand(0, RelocInfo::NONE));
}
frame_->CallRuntime(Runtime::kDeclareContextSlot, 4);
@@ -4612,7 +4612,8 @@
// Get the absolute untagged value of the exponent and use that for the
// calculation.
__ mov(scratch1, Operand(exponent, ASR, kSmiTagSize), SetCC);
- __ rsb(scratch1, scratch1, Operand(0), LeaveCC, mi); // Negate if negative.
+ // Negate if negative.
+ __ rsb(scratch1, scratch1, Operand(0, RelocInfo::NONE), LeaveCC, mi);
__ vmov(d2, d0, mi); // 1.0 needed in d2 later if exponent is negative.
// Run through all the bits in the exponent. The result is calculated in d0
@@ -4625,14 +4626,14 @@
__ b(ne, &more_bits);
// If exponent is positive we are done.
- __ cmp(exponent, Operand(0));
+ __ cmp(exponent, Operand(0, RelocInfo::NONE));
__ b(ge, &allocate_return);
// If exponent is negative result is 1/result (d2 already holds 1.0 in that
// case). However if d0 has reached infinity this will not provide the
// correct result, so call runtime if that is the case.
__ mov(scratch2, Operand(0x7FF00000));
- __ mov(scratch1, Operand(0));
+ __ mov(scratch1, Operand(0, RelocInfo::NONE));
__ vmov(d1, scratch1, scratch2); // Load infinity into d1.
__ vcmp(d0, d1);
__ vmrs(pc);
@@ -5135,7 +5136,7 @@
__ jmp(exit_label());
__ bind(&false_result);
// Set false result.
- __ mov(map_result_, Operand(0));
+ __ mov(map_result_, Operand(0, RelocInfo::NONE));
}
private:
@@ -5309,7 +5310,7 @@
// Move 0x41300000xxxxxxxx (x = random bits) to VFP.
__ vmov(d7, r0, r1);
// Move 0x4130000000000000 to VFP.
- __ mov(r0, Operand(0));
+ __ mov(r0, Operand(0, RelocInfo::NONE));
__ vmov(d8, r0, r1);
// Subtract and store the result in the heap number.
__ vsub(d7, d7, d8);
diff --git a/src/arm/debug-arm.cc b/src/arm/debug-arm.cc
index 82f93b6..8128f7d 100644
--- a/src/arm/debug-arm.cc
+++ b/src/arm/debug-arm.cc
@@ -158,7 +158,7 @@
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
- __ mov(r0, Operand(0)); // no arguments
+ __ mov(r0, Operand(0, RelocInfo::NONE)); // no arguments
__ mov(r1, Operand(ExternalReference::debug_break()));
CEntryStub ceb(1);
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 912fefc..f32da6d 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -688,7 +688,7 @@
CompareStub stub(eq, true, kBothCouldBeNaN, true, r1, r0);
__ CallStub(&stub);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
__ b(ne, &next_test);
__ Drop(1); // Switch value is no longer needed.
__ b(clause->body_target()->entry_label());
@@ -2132,7 +2132,7 @@
// Move 0x41300000xxxxxxxx (x = random bits) to VFP.
__ vmov(d7, r0, r1);
// Move 0x4130000000000000 to VFP.
- __ mov(r0, Operand(0));
+ __ mov(r0, Operand(0, RelocInfo::NONE));
__ vmov(d8, r0, r1);
// Subtract and store the result in the heap number.
__ vsub(d7, d7, d8);
@@ -3125,7 +3125,7 @@
CompareStub stub(cc, strict, kBothCouldBeNaN, true, r1, r0);
__ CallStub(&stub);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
Split(cc, if_true, if_false, fall_through);
}
}
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 49d7b2d..1a76db2 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1292,7 +1292,7 @@
__ mov(loword, Operand(hiword, LSL, mantissa_shift_for_lo_word));
__ orr(hiword, scratch, Operand(hiword, LSR, mantissa_shift_for_hi_word));
} else {
- __ mov(loword, Operand(0));
+ __ mov(loword, Operand(0, RelocInfo::NONE));
__ orr(hiword, scratch, Operand(hiword, LSL, mantissa_shift_for_hi_word));
}
@@ -1790,7 +1790,7 @@
__ and_(fval, ival, Operand(kBinary32SignMask), SetCC);
// Negate value if it is negative.
- __ rsb(ival, ival, Operand(0), LeaveCC, ne);
+ __ rsb(ival, ival, Operand(0, RelocInfo::NONE), LeaveCC, ne);
// We have -1, 0 or 1, which we treat specially. Register ival contains
// absolute value: it is either equal to 1 (special case of -1 and 1),
@@ -2075,18 +2075,18 @@
// and infinities. All these should be converted to 0.
__ mov(r7, Operand(HeapNumber::kExponentMask));
__ and_(r9, r5, Operand(r7), SetCC);
- __ mov(r5, Operand(0), LeaveCC, eq);
+ __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
__ b(eq, &done);
__ teq(r9, Operand(r7));
- __ mov(r5, Operand(0), LeaveCC, eq);
+ __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
__ b(eq, &done);
// Unbias exponent.
__ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
__ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
// If exponent is negative than result is 0.
- __ mov(r5, Operand(0), LeaveCC, mi);
+ __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, mi);
__ b(mi, &done);
// If exponent is too big than result is minimal value.
@@ -2102,14 +2102,14 @@
__ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
__ b(pl, &sign);
- __ rsb(r9, r9, Operand(0));
+ __ rsb(r9, r9, Operand(0, RelocInfo::NONE));
__ mov(r5, Operand(r5, LSL, r9));
__ rsb(r9, r9, Operand(meaningfull_bits));
__ orr(r5, r5, Operand(r6, LSR, r9));
__ bind(&sign);
- __ teq(r7, Operand(0));
- __ rsb(r5, r5, Operand(0), LeaveCC, ne);
+ __ teq(r7, Operand(0, RelocInfo::NONE));
+ __ rsb(r5, r5, Operand(0, RelocInfo::NONE), LeaveCC, ne);
__ bind(&done);
switch (array_type) {
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 36a36be..3554431 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -226,7 +226,7 @@
}
int32_t immediate = src2.immediate();
if (immediate == 0) {
- mov(dst, Operand(0), LeaveCC, cond);
+ mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, cond);
return;
}
if (IsPowerOf2(immediate + 1) && ((immediate & 1) != 0)) {
@@ -305,7 +305,7 @@
}
tst(dst, Operand(~satval));
b(eq, &done);
- mov(dst, Operand(0), LeaveCC, mi); // 0 if negative.
+ mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, mi); // 0 if negative.
mov(dst, Operand(satval), LeaveCC, pl); // satval if positive.
bind(&done);
} else {
@@ -594,7 +594,7 @@
void MacroAssembler::LeaveExitFrame() {
// Clear top frame.
- mov(r3, Operand(0));
+ mov(r3, Operand(0, RelocInfo::NONE));
mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
str(r3, MemOperand(ip));
@@ -763,7 +763,7 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() {
ASSERT(allow_stub_calls());
- mov(r0, Operand(0));
+ mov(r0, Operand(0, RelocInfo::NONE));
mov(r1, Operand(ExternalReference(Runtime::kDebugBreak)));
CEntryStub ces(1);
Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
@@ -799,7 +799,7 @@
// The frame pointer does not point to a JS frame so we save NULL
// for fp. We expect the code throwing an exception to check fp
// before dereferencing it to restore the context.
- mov(ip, Operand(0)); // To save a NULL frame pointer.
+ mov(ip, Operand(0, RelocInfo::NONE)); // To save a NULL frame pointer.
mov(r6, Operand(StackHandler::ENTRY));
ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
&& StackHandlerConstants::kFPOffset == 2 * kPointerSize
@@ -838,7 +838,7 @@
ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
// In debug mode, make sure the lexical context is set.
#ifdef DEBUG
- cmp(scratch, Operand(0));
+ cmp(scratch, Operand(0, RelocInfo::NONE));
Check(ne, "we should not have an empty lexical context");
#endif
@@ -1373,7 +1373,7 @@
HeapNumber::kExponentBits);
// Load dest with zero. We use this either for the final shift or
// for the answer.
- mov(dest, Operand(0));
+ mov(dest, Operand(0, RelocInfo::NONE));
// Check whether the exponent matches a 32 bit signed int that is not a Smi.
// A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is
// the exponent that we are fastest at and also the highest exponent we can
@@ -1427,7 +1427,7 @@
// Move down according to the exponent.
mov(dest, Operand(scratch, LSR, dest));
// Fix sign if sign bit was set.
- rsb(dest, dest, Operand(0), LeaveCC, ne);
+ rsb(dest, dest, Operand(0, RelocInfo::NONE), LeaveCC, ne);
bind(&done);
}
}
@@ -1818,7 +1818,7 @@
#ifdef CAN_USE_ARMV5_INSTRUCTIONS
clz(zeros, source); // This instruction is only supported after ARM5.
#else
- mov(zeros, Operand(0));
+ mov(zeros, Operand(0, RelocInfo::NONE));
Move(scratch, source);
// Top 16.
tst(scratch, Operand(0xffff0000));
diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
index 72b635f..8f45886 100644
--- a/src/arm/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -189,7 +189,7 @@
Label not_at_start;
// Did we start the match at the start of the string at all?
__ ldr(r0, MemOperand(frame_pointer(), kAtStart));
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
BranchOrBacktrack(eq, ¬_at_start);
// If we did, are we still at the start of the input?
@@ -204,7 +204,7 @@
void RegExpMacroAssemblerARM::CheckNotAtStart(Label* on_not_at_start) {
// Did we start the match at the start of the string at all?
__ ldr(r0, MemOperand(frame_pointer(), kAtStart));
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
BranchOrBacktrack(eq, on_not_at_start);
// If we did, are we still at the start of the input?
__ ldr(r1, MemOperand(frame_pointer(), kInputStart));
@@ -364,7 +364,7 @@
__ CallCFunction(function, argument_count);
// Check if function returned non-zero for success or zero for failure.
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
BranchOrBacktrack(eq, on_no_match);
// On success, increment position by length of capture.
__ add(current_input_offset(), current_input_offset(), Operand(r4));
@@ -634,7 +634,7 @@
__ bind(&stack_limit_hit);
CallCheckStackGuardState(r0);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
// If returned value is non-zero, we exit with the returned value as result.
__ b(ne, &exit_label_);
@@ -661,7 +661,7 @@
// string, and store that value in a local variable.
__ tst(r1, Operand(r1));
__ mov(r1, Operand(1), LeaveCC, eq);
- __ mov(r1, Operand(0), LeaveCC, ne);
+ __ mov(r1, Operand(0, RelocInfo::NONE), LeaveCC, ne);
__ str(r1, MemOperand(frame_pointer(), kAtStart));
if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
@@ -684,7 +684,7 @@
// Load previous char as initial value of current character register.
Label at_start;
__ ldr(r0, MemOperand(frame_pointer(), kAtStart));
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
__ b(ne, &at_start);
LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
__ jmp(&start_label_);
@@ -751,7 +751,7 @@
SafeCallTarget(&check_preempt_label_);
CallCheckStackGuardState(r0);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
// If returning non-zero, we should end execution with the given
// result as return value.
__ b(ne, &exit_label_);
@@ -778,7 +778,7 @@
__ CallCFunction(grow_stack, num_arguments);
// If return NULL, we have failed to grow the stack, and
// must exit with a stack-overflow exception.
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand(0, RelocInfo::NONE));
__ b(eq, &exit_with_exception);
// Otherwise use return value as new stack pointer.
__ mov(backtrack_stackpointer(), r0);
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index 59cbad9..5ffebfb 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -825,7 +825,7 @@
void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
Comment cmnt(masm_, "[ WhileStatement");
- Label body, stack_limit_hit, stack_check_success;
+ Label body, stack_limit_hit, stack_check_success, done;
Iteration loop_statement(this, stmt);
increment_loop_depth();
@@ -833,11 +833,6 @@
// Emit the test at the bottom of the loop.
__ jmp(loop_statement.continue_target());
- __ bind(&stack_limit_hit);
- StackCheckStub stack_stub;
- __ CallStub(&stack_stub);
- __ jmp(&stack_check_success);
-
__ bind(&body);
Visit(stmt->body());
__ bind(loop_statement.continue_target());
@@ -856,6 +851,14 @@
loop_statement.break_target());
__ bind(loop_statement.break_target());
+ __ jmp(&done);
+
+ __ bind(&stack_limit_hit);
+ StackCheckStub stack_stub;
+ __ CallStub(&stack_stub);
+ __ jmp(&stack_check_success);
+
+ __ bind(&done);
decrement_loop_depth();
}
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index bfd2650..366b91e 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -1001,15 +1001,16 @@
}
}
+ // If all else fails, use the runtime system to get the correct
+ // result. If arguments was passed in registers now place them on the
+ // stack in the correct order below the return address.
+
// Avoid hitting the string ADD code below when allocation fails in
// the floating point code above.
if (op_ != Token::ADD) {
__ bind(&call_runtime);
}
- // If all else fails, use the runtime system to get the correct
- // result. If arguments was passed in registers now place them on the
- // stack in the correct order below the return address.
if (HasArgsInRegisters()) {
GenerateRegisterArgsPush(masm);
}
@@ -1044,12 +1045,13 @@
StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
__ TailCallStub(&string_add_left_stub);
+ Label call_runtime_with_args;
// Left operand is not a string, test right.
__ bind(&lhs_not_string);
__ test(rhs, Immediate(kSmiTagMask));
- __ j(zero, &call_runtime);
+ __ j(zero, &call_runtime_with_args);
__ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx);
- __ j(above_equal, &call_runtime);
+ __ j(above_equal, &call_runtime_with_args);
StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
__ TailCallStub(&string_add_right_stub);
@@ -1059,6 +1061,7 @@
if (HasArgsInRegisters()) {
GenerateRegisterArgsPush(masm);
}
+ __ bind(&call_runtime_with_args);
__ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
break;
}
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 162b3d6..a9e852e 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -643,9 +643,13 @@
#endif
StaticMarkingVisitor::EnableCodeFlushing(true);
+ // Ensure that empty descriptor array is marked. Method MarkDescriptorArray
+ // relies on it being marked before any other descriptor array.
+ MarkObject(Heap::raw_unchecked_empty_descriptor_array());
+
// Make sure we are not referencing the code from the stack.
for (StackFrameIterator it; !it.done(); it.Advance()) {
- MarkCompactCollector::MarkObject(it.frame()->unchecked_code());
+ MarkObject(it.frame()->unchecked_code());
}
// Iterate the archived stacks in all threads to check if
@@ -656,7 +660,7 @@
SharedFunctionInfoMarkingVisitor visitor;
CompilationCache::IterateFunctions(&visitor);
- MarkCompactCollector::ProcessMarkingStack();
+ ProcessMarkingStack();
}
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 26fea25..9532938 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -94,7 +94,7 @@
// args
// Clear the context before we push it when entering the JS frame.
- __ li(cp, Operand(0));
+ __ li(cp, Operand(0, RelocInfo::NONE));
// Enter an internal frame.
__ EnterInternalFrame();
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 2a54062..bac224f 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2109,7 +2109,16 @@
}
-INT_ACCESSORS(Map, visitor_id, kScavengerCallbackOffset)
+int Map::visitor_id() {
+ return READ_BYTE_FIELD(this, kVisitorIdOffset);
+}
+
+
+void Map::set_visitor_id(int id) {
+ ASSERT(0 <= id && id < 256);
+ WRITE_BYTE_FIELD(this, kVisitorIdOffset, static_cast<byte>(id));
+}
+
int Map::instance_size() {
return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2;
diff --git a/src/objects-visiting.h b/src/objects-visiting.h
index 95dc66c..a6d6b12 100644
--- a/src/objects-visiting.h
+++ b/src/objects-visiting.h
@@ -106,6 +106,9 @@
kMinObjectSizeInWords = 2
};
+ // Visitor ID should fit in one byte.
+ STATIC_ASSERT(kVisitorIdCount <= 256);
+
// Determine which specialized visitor should be used for given instance type
// and instance type.
static VisitorId GetVisitorId(int instance_type, int instance_size);
diff --git a/src/objects.cc b/src/objects.cc
index 9b43d24..ef51851 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2126,9 +2126,6 @@
// The cached map should match newly created normalized map bit-by-bit.
Object* fresh = fast->CopyNormalized(mode);
if (!fresh->IsFailure()) {
- // Copy the unused byte so that the assertion below works.
- Map::cast(fresh)->address()[Map::kUnusedOffset] =
- Map::cast(result)->address()[Map::kUnusedOffset];
ASSERT(memcmp(Map::cast(fresh)->address(),
Map::cast(result)->address(),
Map::kSize) == 0);
@@ -4991,17 +4988,20 @@
}
-uint32_t StringHasher::MakeCachedArrayIndex(uint32_t value, int length) {
- value <<= String::kHashShift;
+uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
// For array indexes mix the length into the hash as an array index could
// be zero.
ASSERT(length > 0);
ASSERT(length <= String::kMaxArrayIndexSize);
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
(1 << String::kArrayIndexValueBits));
- ASSERT(String::kMaxArrayIndexSize < (1 << String::kArrayIndexValueBits));
- value &= ~String::kIsNotArrayIndexMask;
+
+ value <<= String::kHashShift;
value |= length << String::kArrayIndexHashLengthShift;
+
+ ASSERT((value & String::kIsNotArrayIndexMask) == 0);
+ ASSERT((length > String::kMaxCachedArrayIndexLength) ||
+ (value & String::kContainsCachedArrayIndexMask) == 0);
return value;
}
@@ -5010,7 +5010,7 @@
ASSERT(is_valid());
if (length_ <= String::kMaxHashCalcLength) {
if (is_array_index()) {
- return MakeCachedArrayIndex(array_index(), length_);
+ return MakeArrayIndexHash(array_index(), length_);
}
return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
} else {
diff --git a/src/objects.h b/src/objects.h
index 11d65ef..7f6538c 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -3245,8 +3245,7 @@
static const int kInstanceDescriptorsOffset =
kConstructorOffset + kPointerSize;
static const int kCodeCacheOffset = kInstanceDescriptorsOffset + kPointerSize;
- static const int kScavengerCallbackOffset = kCodeCacheOffset + kPointerSize;
- static const int kPadStart = kScavengerCallbackOffset + kPointerSize;
+ static const int kPadStart = kCodeCacheOffset + kPointerSize;
static const int kSize = MAP_POINTER_ALIGN(kPadStart);
// Layout of pointer fields. Heap iteration code relies on them
@@ -3263,9 +3262,8 @@
static const int kPreAllocatedPropertyFieldsByte = 2;
static const int kPreAllocatedPropertyFieldsOffset =
kInstanceSizesOffset + kPreAllocatedPropertyFieldsByte;
- // The byte at position 3 is not in use at the moment.
- static const int kUnusedByte = 3;
- static const int kUnusedOffset = kInstanceSizesOffset + kUnusedByte;
+ static const int kVisitorIdByte = 3;
+ static const int kVisitorIdOffset = kInstanceSizesOffset + kVisitorIdByte;
// Byte offsets within kInstanceAttributesOffset attributes.
static const int kInstanceTypeOffset = kInstanceAttributesOffset + 0;
@@ -4225,7 +4223,7 @@
// Calculated hash value for a string consisting of 1 to
// String::kMaxArrayIndexSize digits with no leading zeros (except "0").
// value is represented decimal value.
- static uint32_t MakeCachedArrayIndex(uint32_t value, int length);
+ static uint32_t MakeArrayIndexHash(uint32_t value, int length);
private:
@@ -4469,6 +4467,7 @@
kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields;
STATIC_CHECK((kArrayIndexLengthBits > 0));
+ STATIC_CHECK(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits));
static const int kArrayIndexHashLengthShift =
kArrayIndexValueBits + kNofHashBitFields;
diff --git a/src/parser.cc b/src/parser.cc
index b689eb8..7667e89 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -266,6 +266,8 @@
bool Check(Token::Value token);
void ExpectSemicolon(bool* ok);
+ Handle<String> GetSymbol(bool* ok);
+
// Get odd-ball literals.
Literal* GetLiteralUndefined();
Literal* GetLiteralTheHole();
@@ -828,7 +830,7 @@
virtual Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
- virtual Handle<String> LookupSymbol(const char* string, int length) {
+ virtual Handle<String> LookupSymbol(int index, Vector<const char> string) {
return Handle<String>();
}
@@ -869,20 +871,46 @@
// Records the occurrence of a function.
virtual FunctionEntry LogFunction(int start) { return FunctionEntry(); }
+ virtual void LogSymbol(int start, Vector<const char> symbol) {}
// Return the current position in the function entry log.
- virtual int position() { return 0; }
+ virtual int function_position() { return 0; }
+ virtual int symbol_position() { return 0; }
+ virtual int symbol_ids() { return 0; }
virtual void LogError() { }
};
class AstBuildingParserFactory : public ParserFactory {
public:
- AstBuildingParserFactory() : ParserFactory(false) { }
+ explicit AstBuildingParserFactory(int expected_symbols)
+ : ParserFactory(false), symbol_cache_(expected_symbols) { }
virtual Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
- virtual Handle<String> LookupSymbol(const char* string, int length) {
- return Factory::LookupSymbol(Vector<const char>(string, length));
+ virtual Handle<String> LookupSymbol(int symbol_id,
+ Vector<const char> string) {
+ // If there is no preparse data, we have no simpler way to identify similar
+ // symbols.
+ if (symbol_id < 0) return Factory::LookupSymbol(string);
+ return LookupCachedSymbol(symbol_id, string);
+ }
+
+ Handle<String> LookupCachedSymbol(int symbol_id,
+ Vector<const char> string) {
+ // Make sure the cache is large enough to hold the symbol identifier.
+ if (symbol_cache_.length() <= symbol_id) {
+ // Increase length to index + 1.
+ symbol_cache_.AddBlock(Handle<String>::null(),
+ symbol_id + 1 - symbol_cache_.length());
+ }
+ Handle<String> result = symbol_cache_.at(symbol_id);
+ if (result.is_null()) {
+ result = Factory::LookupSymbol(string);
+ symbol_cache_.at(symbol_id) = result;
+ return result;
+ }
+ Counters::total_preparse_symbols_skipped.Increment();
+ return result;
}
virtual Handle<String> EmptySymbol() {
@@ -900,6 +928,8 @@
}
virtual Statement* EmptyStatement();
+ private:
+ List<Handle<String> > symbol_cache_;
};
@@ -907,22 +937,74 @@
public:
ParserRecorder();
virtual FunctionEntry LogFunction(int start);
+ virtual void LogSymbol(int start, Vector<const char> literal) {
+ int hash = vector_hash(literal);
+ HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
+ int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
+ if (id == 0) {
+ // Put (symbol_id_ + 1) into entry and increment it.
+ symbol_id_++;
+ entry->value = reinterpret_cast<void*>(symbol_id_);
+ Vector<Vector<const char> > symbol = symbol_entries_.AddBlock(1, literal);
+ entry->key = &symbol[0];
+ } else {
+ // Log a reuse of an earlier seen symbol.
+ symbol_store_.Add(start);
+ symbol_store_.Add(id - 1);
+ }
+ }
virtual void LogError() { }
virtual void LogMessage(Scanner::Location loc,
const char* message,
Vector<const char*> args);
Vector<unsigned> ExtractData() {
- int total_size = ScriptDataImpl::kHeaderSize + store_.size();
+ int function_size = function_store_.size();
+ int symbol_size = symbol_store_.size();
+ int total_size = ScriptDataImpl::kHeaderSize + function_size + symbol_size;
Vector<unsigned> data = Vector<unsigned>::New(total_size);
+ preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
+ preamble_[ScriptDataImpl::kSymbolCountOffset] = symbol_id_;
memcpy(data.start(), preamble_, sizeof(preamble_));
- if (ScriptDataImpl::kHeaderSize < total_size) {
- store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize, total_size));
+ int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
+ if (function_size > 0) {
+ function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
+ symbol_start));
+ }
+ if (symbol_size > 0) {
+ symbol_store_.WriteTo(data.SubVector(symbol_start, total_size));
}
return data;
}
- virtual int position() { return store_.size(); }
+
+ virtual int function_position() { return function_store_.size(); }
+ virtual int symbol_position() { return symbol_store_.size(); }
+ virtual int symbol_ids() { return symbol_id_; }
private:
- Collector<unsigned> store_;
+ Collector<unsigned> function_store_;
+ Collector<unsigned> symbol_store_;
+ Collector<Vector<const char> > symbol_entries_;
+ HashMap symbol_table_;
+ int symbol_id_;
+
+ static int vector_hash(Vector<const char> string) {
+ int hash = 0;
+ for (int i = 0; i < string.length(); i++) {
+ int c = string[i];
+ hash += c;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ return hash;
+ }
+
+ static bool vector_compare(void* a, void* b) {
+ Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a);
+ Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b);
+ int length = string1->length();
+ if (string2->length() != length) return false;
+ return memcmp(string1->start(), string2->start(), length) == 0;
+ }
+
unsigned preamble_[ScriptDataImpl::kHeaderSize];
#ifdef DEBUG
int prev_start;
@@ -936,19 +1018,19 @@
void ScriptDataImpl::SkipFunctionEntry(int start) {
- ASSERT(index_ + FunctionEntry::kSize <= store_.length());
- ASSERT(static_cast<int>(store_[index_]) == start);
- index_ += FunctionEntry::kSize;
+ ASSERT(function_index_ + FunctionEntry::kSize <= store_.length());
+ ASSERT(static_cast<int>(store_[function_index_]) == start);
+ function_index_ += FunctionEntry::kSize;
}
FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
// The current pre-data entry must be a FunctionEntry with the given
// start position.
- if ((index_ + FunctionEntry::kSize <= store_.length())
- && (static_cast<int>(store_[index_]) == start)) {
- int index = index_;
- index_ += FunctionEntry::kSize;
+ if ((function_index_ + FunctionEntry::kSize <= store_.length())
+ && (static_cast<int>(store_[function_index_]) == start)) {
+ int index = function_index_;
+ function_index_ += FunctionEntry::kSize;
return FunctionEntry(store_.SubVector(index,
index + FunctionEntry::kSize));
}
@@ -956,33 +1038,79 @@
}
-bool ScriptDataImpl::SanityCheck() {
- if (store_.length() < static_cast<int>(ScriptDataImpl::kHeaderSize)) {
- return false;
+int ScriptDataImpl::GetSymbolIdentifier(int start) {
+ int next = symbol_index_ + 2;
+ if (next <= store_.length()
+ && static_cast<int>(store_[symbol_index_]) == start) {
+ symbol_index_ = next;
+ return store_[next - 1];
}
+ return symbol_id_++;
+}
+
+
+
+bool ScriptDataImpl::SanityCheck() {
+ // Check that the header data is valid and doesn't specify
+ // point to positions outside the store.
+ if (store_.length() < ScriptDataImpl::kHeaderSize) return false;
if (magic() != ScriptDataImpl::kMagicNumber) return false;
if (version() != ScriptDataImpl::kCurrentVersion) return false;
+ if (has_error()) {
+ // Extra sane sanity check for error message encoding.
+ if (store_.length() <= kHeaderSize + kMessageTextPos) return false;
+ if (Read(kMessageStartPos) > Read(kMessageEndPos)) return false;
+ unsigned arg_count = Read(kMessageArgCountPos);
+ int pos = kMessageTextPos;
+ for (unsigned int i = 0; i <= arg_count; i++) {
+ if (store_.length() <= kHeaderSize + pos) return false;
+ int length = static_cast<int>(Read(pos));
+ if (length < 0) return false;
+ pos += 1 + length;
+ }
+ if (store_.length() < kHeaderSize + pos) return false;
+ return true;
+ }
+ // Check that the space allocated for function entries is sane.
+ int functions_size =
+ static_cast<int>(store_[ScriptDataImpl::kFunctionsSizeOffset]);
+ if (functions_size < 0) return false;
+ if (functions_size % FunctionEntry::kSize != 0) return false;
+ // Check that the count of symbols is non-negative.
+ int symbol_count =
+ static_cast<int>(store_[ScriptDataImpl::kSymbolCountOffset]);
+ if (symbol_count < 0) return false;
+ // Check that the total size has room both function entries.
+ int minimum_size =
+ ScriptDataImpl::kHeaderSize + functions_size;
+ if (store_.length() < minimum_size) return false;
return true;
}
ParserRecorder::ParserRecorder()
- : store_(0) {
+ : function_store_(0),
+ symbol_store_(0),
+ symbol_entries_(0),
+ symbol_table_(vector_compare),
+ symbol_id_(0) {
#ifdef DEBUG
prev_start = -1;
#endif
preamble_[ScriptDataImpl::kMagicOffset] = ScriptDataImpl::kMagicNumber;
preamble_[ScriptDataImpl::kVersionOffset] = ScriptDataImpl::kCurrentVersion;
preamble_[ScriptDataImpl::kHasErrorOffset] = false;
+ preamble_[ScriptDataImpl::kFunctionsSizeOffset] = 0;
+ preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
preamble_[ScriptDataImpl::kSizeOffset] = 0;
- ASSERT_EQ(4, ScriptDataImpl::kHeaderSize);
+ ASSERT_EQ(6, ScriptDataImpl::kHeaderSize);
}
void ParserRecorder::WriteString(Vector<const char> str) {
- store_.Add(str.length());
+ function_store_.Add(str.length());
for (int i = 0; i < str.length(); i++) {
- store_.Add(str[i]);
+ function_store_.Add(str[i]);
}
}
@@ -1003,10 +1131,14 @@
Vector<const char*> args) {
if (has_error()) return;
preamble_[ScriptDataImpl::kHasErrorOffset] = true;
- store_.Reset();
- store_.Add(loc.beg_pos);
- store_.Add(loc.end_pos);
- store_.Add(args.length());
+ function_store_.Reset();
+ STATIC_ASSERT(ScriptDataImpl::kMessageStartPos == 0);
+ function_store_.Add(loc.beg_pos);
+ STATIC_ASSERT(ScriptDataImpl::kMessageEndPos == 1);
+ function_store_.Add(loc.end_pos);
+ STATIC_ASSERT(ScriptDataImpl::kMessageArgCountPos == 2);
+ function_store_.Add(args.length());
+ STATIC_ASSERT(ScriptDataImpl::kMessageTextPos == 3);
WriteString(CStrVector(message));
for (int i = 0; i < args.length(); i++) {
WriteString(CStrVector(args[i]));
@@ -1015,22 +1147,23 @@
Scanner::Location ScriptDataImpl::MessageLocation() {
- int beg_pos = Read(0);
- int end_pos = Read(1);
+ int beg_pos = Read(kMessageStartPos);
+ int end_pos = Read(kMessageEndPos);
return Scanner::Location(beg_pos, end_pos);
}
const char* ScriptDataImpl::BuildMessage() {
- unsigned* start = ReadAddress(3);
+ unsigned* start = ReadAddress(kMessageTextPos);
return ReadString(start, NULL);
}
Vector<const char*> ScriptDataImpl::BuildArgs() {
- int arg_count = Read(2);
+ int arg_count = Read(kMessageArgCountPos);
const char** array = NewArray<const char*>(arg_count);
- int pos = ScriptDataImpl::kHeaderSize + Read(3);
+ // Position after the string starting at position 3.
+ int pos = kMessageTextPos + 1 + Read(kMessageTextPos);
for (int i = 0; i < arg_count; i++) {
int count = 0;
array[i] = ReadString(ReadAddress(pos), &count);
@@ -1049,14 +1182,6 @@
return &store_[ScriptDataImpl::kHeaderSize + position];
}
-void ScriptDataImpl::FindStart(int position) {
- // Only search forwards, and linearly for now.
- while ((index_ < store_.length())
- && (static_cast<int>(store_[index_])) < position) {
- index_ += FunctionEntry::kSize;
- }
-}
-
FunctionEntry ParserRecorder::LogFunction(int start) {
#ifdef DEBUG
@@ -1064,7 +1189,7 @@
prev_start = start;
#endif
if (has_error()) return FunctionEntry();
- FunctionEntry result(store_.AddBlock(FunctionEntry::kSize, 0));
+ FunctionEntry result(function_store_.AddBlock(FunctionEntry::kSize, 0));
result.set_start_pos(start);
return result;
}
@@ -1074,8 +1199,14 @@
public:
AstBuildingParser(Handle<Script> script, bool allow_natives_syntax,
v8::Extension* extension, ScriptDataImpl* pre_data)
- : Parser(script, allow_natives_syntax, extension, PARSE,
- factory(), log(), pre_data) { }
+ : Parser(script,
+ allow_natives_syntax,
+ extension,
+ PARSE,
+ factory(),
+ log(),
+ pre_data),
+ factory_(pre_data ? pre_data->symbol_count() : 16) { }
virtual void ReportMessageAt(Scanner::Location loc, const char* message,
Vector<const char*> args);
virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
@@ -1442,6 +1573,21 @@
}
+Handle<String> Parser::GetSymbol(bool* ok) {
+ if (pre_data() != NULL) {
+ int symbol_id =
+ pre_data()->GetSymbolIdentifier(scanner_.location().beg_pos);
+ if (symbol_id < 0) {
+ ReportInvalidPreparseData(Factory::empty_symbol(), ok);
+ return Handle<String>::null();
+ }
+ return factory()->LookupSymbol(symbol_id, scanner_.literal());
+ }
+ log()->LogSymbol(scanner_.location().beg_pos, scanner_.literal());
+ return factory()->LookupSymbol(-1, scanner_.literal());
+}
+
+
void AstBuildingParser::ReportMessageAt(Scanner::Location source_location,
const char* type,
Vector<const char*> args) {
@@ -3419,9 +3565,7 @@
case Token::STRING: {
Consume(Token::STRING);
- Handle<String> symbol =
- factory()->LookupSymbol(scanner_.literal_string(),
- scanner_.literal_length());
+ Handle<String> symbol = GetSymbol(CHECK_OK);
result = NEW(Literal(symbol));
if (fni_ != NULL) fni_->PushLiteralName(symbol);
break;
@@ -3689,9 +3833,7 @@
Token::Value next = Next();
// TODO(820): Allow NUMBER and STRING as well (and handle array indices).
if (next == Token::IDENTIFIER || Token::IsKeyword(next)) {
- Handle<String> name =
- factory()->LookupSymbol(scanner_.literal_string(),
- scanner_.literal_length());
+ Handle<String> name = GetSymbol(CHECK_OK);
FunctionLiteral* value =
ParseFunctionLiteral(name,
RelocInfo::kNoPosition,
@@ -3755,9 +3897,7 @@
}
case Token::STRING: {
Consume(Token::STRING);
- Handle<String> string =
- factory()->LookupSymbol(scanner_.literal_string(),
- scanner_.literal_length());
+ Handle<String> string = GetSymbol(CHECK_OK);
if (fni_ != NULL) fni_->PushLiteralName(string);
uint32_t index;
if (!string.is_null() && string->AsArrayIndex(&index)) {
@@ -3777,9 +3917,7 @@
default:
if (Token::IsKeyword(next)) {
Consume(next);
- Handle<String> string =
- factory()->LookupSymbol(scanner_.literal_string(),
- scanner_.literal_length());
+ Handle<String> string = GetSymbol(CHECK_OK);
key = NEW(Literal(string));
} else {
// Unexpected token.
@@ -3972,7 +4110,9 @@
}
Counters::total_preparse_skipped.Increment(end_pos - function_block_pos);
scanner_.SeekForward(end_pos);
- pre_data()->Skip(entry.predata_skip());
+ pre_data()->Skip(entry.predata_function_skip(),
+ entry.predata_symbol_skip(),
+ entry.symbol_id_skip());
materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count();
only_simple_this_property_assignments = false;
@@ -3984,7 +4124,9 @@
pre_data()->SkipFunctionEntry(function_block_pos);
}
FunctionEntry entry = log()->LogFunction(function_block_pos);
- int predata_position_before = log()->position();
+ int predata_function_position_before = log()->function_position();
+ int predata_symbol_position_before = log()->symbol_position();
+ int symbol_ids_before = log()->symbol_ids();
ParseSourceElements(&body, Token::RBRACE, CHECK_OK);
materialized_literal_count = temp_scope.materialized_literal_count();
expected_property_count = temp_scope.expected_property_count();
@@ -3998,7 +4140,12 @@
entry.set_end_pos(end_pos);
entry.set_literal_count(materialized_literal_count);
entry.set_property_count(expected_property_count);
- entry.set_predata_skip(log()->position() - predata_position_before);
+ entry.set_predata_function_skip(
+ log()->function_position() - predata_function_position_before);
+ entry.set_predata_symbol_skip(
+ log()->symbol_position() - predata_symbol_position_before);
+ entry.set_symbol_id_skip(
+ log()->symbol_ids() - symbol_ids_before);
}
}
@@ -4148,8 +4295,7 @@
Handle<String> Parser::ParseIdentifier(bool* ok) {
Expect(Token::IDENTIFIER, ok);
if (!*ok) return Handle<String>();
- return factory()->LookupSymbol(scanner_.literal_string(),
- scanner_.literal_length());
+ return GetSymbol(ok);
}
@@ -4160,8 +4306,7 @@
*ok = false;
return Handle<String>();
}
- return factory()->LookupSymbol(scanner_.literal_string(),
- scanner_.literal_length());
+ return GetSymbol(ok);
}
@@ -4179,8 +4324,7 @@
*is_get = strcmp(token, "get") == 0;
*is_set = !*is_get && strcmp(token, "set") == 0;
}
- return factory()->LookupSymbol(scanner_.literal_string(),
- scanner_.literal_length());
+ return GetSymbol(ok);
}
@@ -4362,8 +4506,7 @@
if (peek() != Token::RBRACE) {
do {
Expect(Token::STRING, CHECK_OK);
- Handle<String> key = factory()->LookupSymbol(scanner_.literal_string(),
- scanner_.literal_length());
+ Handle<String> key = GetSymbol(CHECK_OK);
Expect(Token::COLON, CHECK_OK);
Expression* value = ParseJsonValue(CHECK_OK);
Literal* key_literal;
@@ -5251,7 +5394,7 @@
ScriptDataImpl::~ScriptDataImpl() {
- store_.Dispose();
+ if (owns_store_) store_.Dispose();
}
diff --git a/src/parser.h b/src/parser.h
index 2952581..56412a0 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -72,14 +72,25 @@
backing_[kPropertyCountOffset] = value;
}
- int predata_skip() { return backing_[kPredataSkipOffset]; }
- void set_predata_skip(int value) {
- backing_[kPredataSkipOffset] = value;
+ int predata_function_skip() { return backing_[kPredataFunctionSkipOffset]; }
+ void set_predata_function_skip(int value) {
+ backing_[kPredataFunctionSkipOffset] = value;
}
+ int predata_symbol_skip() { return backing_[kPredataSymbolSkipOffset]; }
+ void set_predata_symbol_skip(int value) {
+ backing_[kPredataSymbolSkipOffset] = value;
+ }
+
+ int symbol_id_skip() { return backing_[kSymbolIdSkipOffset]; }
+ void set_symbol_id_skip(int value) {
+ backing_[kSymbolIdSkipOffset] = value;
+ }
+
+
bool is_valid() { return backing_.length() > 0; }
- static const int kSize = 5;
+ static const int kSize = 7;
private:
Vector<unsigned> backing_;
@@ -87,7 +98,9 @@
static const int kEndPosOffset = 1;
static const int kLiteralCountOffset = 2;
static const int kPropertyCountOffset = 3;
- static const int kPredataSkipOffset = 4;
+ static const int kPredataFunctionSkipOffset = 4;
+ static const int kPredataSymbolSkipOffset = 5;
+ static const int kSymbolIdSkipOffset = 6;
};
@@ -95,12 +108,30 @@
public:
explicit ScriptDataImpl(Vector<unsigned> store)
: store_(store),
- index_(kHeaderSize) { }
+ function_index_(kHeaderSize),
+ symbol_id_(0),
+ owns_store_(true) {
+ Initialize();
+ }
+
+ void Initialize() {
+ if (store_.length() >= kHeaderSize) {
+ // Otherwise we won't satisfy the SanityCheck.
+ symbol_index_ = kHeaderSize + store_[kFunctionsSizeOffset];
+ }
+ }
+
+ // Create an empty ScriptDataImpl that is guaranteed to not satisfy
+ // a SanityCheck.
+ ScriptDataImpl() : store_(Vector<unsigned>()), owns_store_(false) { }
+
virtual ~ScriptDataImpl();
virtual int Length();
virtual const char* Data();
virtual bool HasError();
+
FunctionEntry GetFunctionEntry(int start);
+ int GetSymbolIdentifier(int start);
void SkipFunctionEntry(int start);
bool SanityCheck();
@@ -108,36 +139,67 @@
const char* BuildMessage();
Vector<const char*> BuildArgs();
+ int symbol_count() {
+ return (store_.length() > kHeaderSize) ? store_[kSymbolCountOffset] : 0;
+ }
+ // The following functions should only be called if SanityCheck has
+ // returned true.
bool has_error() { return store_[kHasErrorOffset]; }
unsigned magic() { return store_[kMagicOffset]; }
unsigned version() { return store_[kVersionOffset]; }
+
// Skip forward in the preparser data by the given number
// of unsigned ints.
- virtual void Skip(int entries) {
- ASSERT(entries >= 0);
- ASSERT(entries <= store_.length() - index_);
- index_ += entries;
+ virtual void Skip(int function_entries, int symbol_entries, int symbol_ids) {
+ ASSERT(function_entries >= 0);
+ ASSERT(function_entries
+ <= (static_cast<int>(store_[kFunctionsSizeOffset])
+ - (function_index_ - kHeaderSize)));
+ function_index_ += function_entries;
+ symbol_index_ += symbol_entries;
+ symbol_id_ += symbol_ids;
}
static const unsigned kMagicNumber = 0xBadDead;
- static const unsigned kCurrentVersion = 1;
+ static const unsigned kCurrentVersion = 2;
static const int kMagicOffset = 0;
static const int kVersionOffset = 1;
static const int kHasErrorOffset = 2;
- static const int kSizeOffset = 3;
- static const int kHeaderSize = 4;
+ static const int kFunctionsSizeOffset = 3;
+ static const int kSymbolCountOffset = 4;
+ static const int kSizeOffset = 5;
+ static const int kHeaderSize = 6;
+
+ static const int kMessageStartPos = 0;
+ static const int kMessageEndPos = 1;
+ static const int kMessageArgCountPos = 2;
+ static const int kMessageTextPos = 3;
private:
Vector<unsigned> store_;
- int index_;
+ int function_index_;
+ int symbol_index_;
+ int symbol_id_;
+ bool owns_store_;
unsigned Read(int position);
unsigned* ReadAddress(int position);
- void FindStart(int position);
+ ScriptDataImpl(const char* backing_store, int length)
+ : store_(reinterpret_cast<unsigned*>(const_cast<char*>(backing_store)),
+ length / sizeof(unsigned)),
+ function_index_(kHeaderSize),
+ symbol_id_(0),
+ owns_store_(false) {
+ ASSERT_EQ(0, reinterpret_cast<intptr_t>(backing_store) % sizeof(unsigned));
+ Initialize();
+ }
+
// Read strings written by ParserRecorder::WriteString.
static const char* ReadString(unsigned* start, int* chars);
+
+ friend class ScriptData;
};
diff --git a/src/runtime.cc b/src/runtime.cc
index c7ec6bf..43a6734 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -4677,9 +4677,8 @@
(len == 1 || data[0] != '0')) {
// String hash is not calculated yet but all the data are present.
// Update the hash field to speed up sequential convertions.
- uint32_t hash = StringHasher::MakeCachedArrayIndex(d, len);
+ uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
#ifdef DEBUG
- ASSERT((hash & String::kContainsCachedArrayIndexMask) == 0);
subject->Hash(); // Force hash calculation.
ASSERT_EQ(static_cast<int>(subject->hash_field()),
static_cast<int>(hash));
diff --git a/src/v8-counters.h b/src/v8-counters.h
index af657f1..8c948cc 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -98,6 +98,8 @@
SC(total_parse_size, V8.TotalParseSize) \
/* Amount of source code skipped over using preparsing. */ \
SC(total_preparse_skipped, V8.TotalPreparseSkipped) \
+ /* Number of symbol lookups skipped using preparsing */ \
+ SC(total_preparse_symbols_skipped, V8.TotalPreparseSymbolSkipped) \
/* Amount of compiled source code. */ \
SC(total_compile_size, V8.TotalCompileSize) \
/* Amount of source code compiled with the old codegen. */ \
diff --git a/src/version.cc b/src/version.cc
index 3ba41b7..0af1795 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 4
-#define BUILD_NUMBER 1
+#define BUILD_NUMBER 2
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 4b6fa9c..2b50db7 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -37,6 +37,7 @@
#include "top.h"
#include "utils.h"
#include "cctest.h"
+#include "parser.h"
static const bool kLogThreading = true;
@@ -3605,6 +3606,29 @@
}
+static const char* kNativeCallInExtensionSource =
+ "function call_runtime_last_index_of(x) {"
+ " return %StringLastIndexOf(x, 'bob', 10);"
+ "}";
+
+
+static const char* kNativeCallTest =
+ "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
+
+// Test that a native runtime calls are supported in extensions.
+THREADED_TEST(NativeCallInExtensions) {
+ v8::HandleScope handle_scope;
+ v8::RegisterExtension(new Extension("nativecall",
+ kNativeCallInExtensionSource));
+ const char* extension_names[] = { "nativecall" };
+ v8::ExtensionConfiguration extensions(1, extension_names);
+ v8::Handle<Context> context = Context::New(&extensions);
+ Context::Scope lock(context);
+ v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
+ CHECK_EQ(result, v8::Integer::New(3));
+}
+
+
static void CheckDependencies(const char* name, const char* expected) {
v8::HandleScope handle_scope;
v8::ExtensionConfiguration config(1, &name);
@@ -8601,15 +8625,12 @@
v8::ScriptData::PreCompile(script, i::StrLength(script));
CHECK(!sd->HasError());
// ScriptDataImpl private implementation details
- const int kUnsignedSize = sizeof(unsigned);
- const int kHeaderSize = 4;
- const int kFunctionEntrySize = 5;
+ const int kHeaderSize = i::ScriptDataImpl::kHeaderSize;
+ const int kFunctionEntrySize = i::FunctionEntry::kSize;
const int kFunctionEntryStartOffset = 0;
const int kFunctionEntryEndOffset = 1;
unsigned* sd_data =
reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
- CHECK_EQ(sd->Length(),
- (kHeaderSize + 2 * kFunctionEntrySize) * kUnsignedSize);
// Overwrite function bar's end position with 0.
sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc
index fee6624..7c669d3 100644
--- a/test/cctest/test-assembler-arm.cc
+++ b/test/cctest/test-assembler-arm.cc
@@ -91,7 +91,7 @@
Label L, C;
__ mov(r1, Operand(r0));
- __ mov(r0, Operand(0));
+ __ mov(r0, Operand(0, RelocInfo::NONE));
__ b(&C);
__ bind(&L);
@@ -99,7 +99,7 @@
__ sub(r1, r1, Operand(1));
__ bind(&C);
- __ teq(r1, Operand(0));
+ __ teq(r1, Operand(0, RelocInfo::NONE));
__ b(ne, &L);
__ mov(pc, Operand(lr));
@@ -135,7 +135,7 @@
__ sub(r1, r1, Operand(1));
__ bind(&C);
- __ teq(r1, Operand(0));
+ __ teq(r1, Operand(0, RelocInfo::NONE));
__ b(ne, &L);
__ mov(pc, Operand(lr));
diff --git a/test/cctest/test-assembler-mips.cc b/test/cctest/test-assembler-mips.cc
index 0a2310e..955562b 100644
--- a/test/cctest/test-assembler-mips.cc
+++ b/test/cctest/test-assembler-mips.cc
@@ -109,7 +109,7 @@
__ bind(&C);
__ xori(v1, a1, 0);
- __ Branch(ne, &L, v1, Operand(0));
+ __ Branch(ne, &L, v1, Operand(0, RelocInfo::NONE));
__ nop();
__ jr(ra);
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 9531b57..f5526ce 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -4591,6 +4591,18 @@
}
+// We match parts of the message to get source line.
+int GetSourceLineFromBreakEventMessage(char *message) {
+ const char* source_line = "\"sourceLine\":";
+ char* pos = strstr(message, source_line);
+ if (pos == NULL) {
+ return -1;
+ }
+ int res = -1;
+ res = StringToInt(pos + strlen(source_line));
+ return res;
+}
+
/* Test MessageQueues */
/* Tests the message queues that hold debugger commands and
* response messages to the debugger. Fills queues and makes
@@ -4870,6 +4882,9 @@
v8::String::Value json(message.GetJSON());
Utf16ToAscii(*json, json.length(), print_buffer);
if (IsBreakEventMessage(print_buffer)) {
+ // Check that we are inside the while loop.
+ int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
+ CHECK(8 <= source_line && source_line <= 13);
threaded_debugging_barriers.barrier_2.Wait();
}
}
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index ed0c8b5..5ddd044 100755
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -31,6 +31,7 @@
#include "token.h"
#include "scanner.h"
+#include "parser.h"
#include "utils.h"
#include "execution.h"
@@ -148,7 +149,7 @@
NULL
};
- // Parser needs a stack limit.
+ // Parser/Scanner needs a stack limit.
int marker;
i::StackGuard::SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
@@ -160,3 +161,81 @@
delete data;
}
}
+
+
+class ScriptResource : public v8::String::ExternalAsciiStringResource {
+ public:
+ ScriptResource(const char* data, size_t length)
+ : data_(data), length_(length) { }
+
+ const char* data() const { return data_; }
+ size_t length() const { return length_; }
+
+ private:
+ const char* data_;
+ size_t length_;
+};
+
+
+TEST(Preparsing) {
+ v8::HandleScope handles;
+ v8::Persistent<v8::Context> context = v8::Context::New();
+ v8::Context::Scope context_scope(context);
+ int marker;
+ i::StackGuard::SetStackLimit(
+ reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+ // Source containing functions that might be lazily compiled and all types
+ // of symbols (string, propertyName, regexp).
+ const char* source =
+ "var x = 42;"
+ "function foo(a) { return function nolazy(b) { return a + b; } }"
+ "function bar(a) { if (a) return function lazy(b) { return b; } }"
+ "var z = {'string': 'string literal', bareword: 'propertyName', "
+ " 42: 'number literal', for: 'keyword as propertyName', "
+ " f\\u006fr: 'keyword propertyname with escape'};"
+ "var v = /RegExp Literal/;"
+ "var w = /RegExp Literal\\u0020With Escape/gin;"
+ "var y = { get getter() { return 42; }, "
+ " set setter(v) { this.value = v; }};";
+ int source_length = strlen(source);
+ const char* error_source = "var x = y z;";
+ int error_source_length = strlen(error_source);
+
+ v8::ScriptData* preparse =
+ v8::ScriptData::PreCompile(source, source_length);
+ CHECK(!preparse->HasError());
+ bool lazy_flag = i::FLAG_lazy;
+ {
+ i::FLAG_lazy = true;
+ ScriptResource* resource = new ScriptResource(source, source_length);
+ v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
+ v8::Script::Compile(script_source, NULL, preparse);
+ }
+
+ {
+ i::FLAG_lazy = false;
+
+ ScriptResource* resource = new ScriptResource(source, source_length);
+ v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
+ v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
+ }
+ delete preparse;
+ i::FLAG_lazy = lazy_flag;
+
+ // Syntax error.
+ v8::ScriptData* error_preparse =
+ v8::ScriptData::PreCompile(error_source, error_source_length);
+ CHECK(error_preparse->HasError());
+ i::ScriptDataImpl *pre_impl =
+ reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
+ i::Scanner::Location error_location =
+ pre_impl->MessageLocation();
+ // Error is at "z" in source, location 10..11.
+ CHECK_EQ(10, error_location.beg_pos);
+ CHECK_EQ(11, error_location.end_pos);
+ // Should not crash.
+ const char* message = pre_impl->BuildMessage();
+ i::Vector<const char*> args = pre_impl->BuildArgs();
+ CHECK_GT(strlen(message), 0);
+}
diff --git a/test/mjsunit/regress/regress-push-args-twice.js b/test/mjsunit/regress/regress-push-args-twice.js
new file mode 100644
index 0000000..faa6007
--- /dev/null
+++ b/test/mjsunit/regress/regress-push-args-twice.js
@@ -0,0 +1,37 @@
+// 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.
+
+// Check that the ADD binary op stub correctly handles non-number arguments
+// passed on registers.
+
+try {
+ for (var key = 0; key != 10; key++) {
+ var x = 1 + undefined;
+ }
+} catch(e) {
+ fail("no exception", e);
+}
diff --git a/test/mjsunit/str-to-num.js b/test/mjsunit/str-to-num.js
index 20e2986..28e98d9 100644
--- a/test/mjsunit/str-to-num.js
+++ b/test/mjsunit/str-to-num.js
@@ -203,3 +203,7 @@
assertTrue(isNaN(toNumber("1e")), "1e");
assertTrue(isNaN(toNumber("1e ")), "1e_");
assertTrue(isNaN(toNumber("1" + repeat('0', 1000) + 'junk')), "1e1000 junk");
+
+for (var i = 1; i < 12; i++) {
+ assertEquals(toNumber('1' + repeat('0', i)), Math.pow(10.0, i));
+}