Version 3.16.3
Improved GC performance when moving parts of a FixedArray (issue 2452).
Enabled readline on d8 while building a shared lib (issue 1781).
Fixed missing exception check in typed array constructor (Chromium issue 168545).
Check for read-only-ness when preparing for array sort (issue 2419).
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@13346 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index b926c22..352b63d 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -3124,7 +3124,7 @@
} else {
i::Handle<i::String> class_name = i::Handle<i::String>::cast(name);
- if (class_name->IsEqualTo(i::CStrVector("Arguments"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Arguments"))) {
return v8::String::New("[object Object]");
} else {
@@ -4145,11 +4145,14 @@
FlattenString(str); // Flatten the string for efficiency.
}
- if (str->IsOneByteRepresentation()) {
+ if (str->HasOnlyAsciiChars()) {
// WriteToFlat is faster than using the StringCharacterStream.
if (length == -1) length = str->length() + 1;
int len = i::Min(length, str->length() - start);
- i::String::WriteToFlat(*str, buffer, start, start + len);
+ i::String::WriteToFlat(*str,
+ reinterpret_cast<uint8_t*>(buffer),
+ start,
+ start + len);
if (!(options & PRESERVE_ASCII_NULL)) {
for (int i = 0; i < len; i++) {
if (buffer[i] == '\0') buffer[i] = ' ';
@@ -5183,14 +5186,14 @@
static i::Handle<i::String> RegExpFlagsToString(RegExp::Flags flags) {
- char flags_buf[3];
+ uint8_t flags_buf[3];
int num_flags = 0;
if ((flags & RegExp::kGlobal) != 0) flags_buf[num_flags++] = 'g';
if ((flags & RegExp::kMultiline) != 0) flags_buf[num_flags++] = 'm';
if ((flags & RegExp::kIgnoreCase) != 0) flags_buf[num_flags++] = 'i';
ASSERT(num_flags <= static_cast<int>(ARRAY_SIZE(flags_buf)));
return FACTORY->LookupOneByteSymbol(
- i::Vector<const char>(flags_buf, num_flags));
+ i::Vector<const uint8_t>(flags_buf, num_flags));
}
diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h
index a31b7e9..02dc907 100644
--- a/src/arm/assembler-arm-inl.h
+++ b/src/arm/assembler-arm-inl.h
@@ -344,7 +344,7 @@
Operand::Operand(Smi* value) {
rm_ = no_reg;
imm32_ = reinterpret_cast<intptr_t>(value);
- rmode_ = RelocInfo::NONE;
+ rmode_ = RelocInfo::NONE32;
}
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 9cd8675..b80e23d 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -234,7 +234,7 @@
} else {
// no relocation needed
imm32_ = reinterpret_cast<intptr_t>(obj);
- rmode_ = RelocInfo::NONE;
+ rmode_ = RelocInfo::NONE32;
}
}
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index ca63288..27befaa 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -386,7 +386,7 @@
public:
// immediate
INLINE(explicit Operand(int32_t immediate,
- RelocInfo::Mode rmode = RelocInfo::NONE));
+ RelocInfo::Mode rmode = RelocInfo::NONE32));
INLINE(static Operand Zero()) {
return Operand(static_cast<int32_t>(0));
}
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 28e00dd..3be8e92 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -140,7 +140,7 @@
__ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
__ str(scratch1, FieldMemOperand(result, JSArray::kPropertiesOffset));
// Field JSArray::kElementsOffset is initialized later.
- __ mov(scratch3, Operand(0, RelocInfo::NONE));
+ __ mov(scratch3, Operand::Zero());
__ str(scratch3, FieldMemOperand(result, JSArray::kLengthOffset));
if (initial_capacity == 0) {
@@ -319,7 +319,7 @@
has_non_smi_element, finish, cant_transition_map, not_double;
// Check for array construction with zero arguments or one.
- __ cmp(r0, Operand(0, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
__ b(ne, &argc_one_or_more);
// Handle construction of an empty array.
@@ -347,7 +347,7 @@
__ tst(r2, r2);
__ b(ne, ¬_empty_array);
__ Drop(1); // Adjust stack.
- __ mov(r0, Operand(0)); // Treat this as a call with argc of zero.
+ __ mov(r0, Operand::Zero()); // Treat this as a call with argc of zero.
__ b(&empty_array);
__ bind(¬_empty_array);
@@ -590,7 +590,7 @@
// Load the first arguments in r0 and get rid of the rest.
Label no_arguments;
- __ cmp(r0, Operand(0, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
__ b(eq, &no_arguments);
// First args = sp[(argc - 1) * 4].
__ sub(r0, r0, Operand(1));
@@ -634,7 +634,7 @@
__ cmp(r4, Operand(JSValue::kSize >> kPointerSizeLog2));
__ Assert(eq, "Unexpected string wrapper instance size");
__ ldrb(r4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset));
- __ cmp(r4, Operand(0, RelocInfo::NONE));
+ __ cmp(r4, Operand::Zero());
__ Assert(eq, "Unexpected unused properties of string wrapper");
}
__ str(map, FieldMemOperand(r0, HeapObject::kMapOffset));
@@ -1097,7 +1097,7 @@
// r5-r7, cp may be clobbered
// Clear the context before we push it when entering the internal frame.
- __ mov(cp, Operand(0, RelocInfo::NONE));
+ __ mov(cp, Operand::Zero());
// Enter an internal frame.
{
@@ -1259,7 +1259,7 @@
#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
-void Builtins::Generate_NotifyICMiss(MacroAssembler* masm) {
+void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
@@ -1268,7 +1268,7 @@
// registers.
__ stm(db_w, sp, kJSCallerSaved | kCalleeSaved);
// Pass the function and deoptimization type to the runtime system.
- __ CallRuntime(Runtime::kNotifyICMiss, 0);
+ __ CallRuntime(Runtime::kNotifyStubFailure, 0);
__ ldm(ia_w, sp, kJSCallerSaved | kCalleeSaved);
}
@@ -1375,7 +1375,7 @@
// 1. Make sure we have at least one argument.
// r0: actual number of arguments
{ Label done;
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
__ b(ne, &done);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2);
@@ -1396,7 +1396,7 @@
// r0: actual number of arguments
// r1: function
Label shift_arguments;
- __ mov(r4, Operand(0, RelocInfo::NONE)); // indicate regular JS_FUNCTION
+ __ mov(r4, Operand::Zero()); // indicate regular JS_FUNCTION
{ Label convert_to_object, use_global_receiver, patch_receiver;
// Change context eagerly in case we need the global receiver.
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
@@ -1451,7 +1451,7 @@
// Restore the function to r1, and the flag to r4.
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
- __ mov(r4, Operand(0, RelocInfo::NONE));
+ __ mov(r4, Operand::Zero());
__ jmp(&patch_receiver);
// Use the global receiver object from the called function as the
@@ -1473,11 +1473,11 @@
// 3b. Check for function proxy.
__ bind(&slow);
- __ mov(r4, Operand(1, RelocInfo::NONE)); // indicate function proxy
+ __ mov(r4, Operand(1, RelocInfo::NONE32)); // indicate function proxy
__ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
__ b(eq, &shift_arguments);
__ bind(&non_function);
- __ mov(r4, Operand(2, RelocInfo::NONE)); // indicate non-function
+ __ mov(r4, Operand(2, RelocInfo::NONE32)); // indicate non-function
// 3c. Patch the first argument when calling a non-function. The
// CALL_NON_FUNCTION builtin expects the non-function callee as
@@ -1521,7 +1521,7 @@
__ tst(r4, r4);
__ b(eq, &function);
// Expected number of arguments is 0 for CALL_NON_FUNCTION.
- __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ mov(r2, Operand::Zero());
__ SetCallKind(r5, CALL_AS_METHOD);
__ cmp(r4, Operand(1));
__ b(ne, &non_proxy);
@@ -1599,7 +1599,7 @@
// Push current limit and index.
__ bind(&okay);
__ push(r0); // limit
- __ mov(r1, Operand(0, RelocInfo::NONE)); // initial index
+ __ mov(r1, Operand::Zero()); // initial index
__ push(r1);
// Get the receiver.
@@ -1711,7 +1711,7 @@
__ bind(&call_proxy);
__ push(r1); // add function proxy as last argument
__ add(r0, r0, Operand(1));
- __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ mov(r2, Operand::Zero());
__ SetCallKind(r5, CALL_AS_METHOD);
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
__ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 3ab09a2..e5c1c3e 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -44,7 +44,7 @@
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
- isolate->builtins()->KeyedLoadIC_Miss();
+ FUNCTION_ADDR(KeyedLoadIC_Miss);
}
@@ -344,6 +344,7 @@
MacroAssembler* masm,
int length,
FastCloneShallowArrayStub::Mode mode,
+ AllocationSiteInfoMode allocation_site_info_mode,
Label* fail) {
// Registers on entry:
//
@@ -357,7 +358,12 @@
? FixedDoubleArray::SizeFor(length)
: FixedArray::SizeFor(length);
}
- int size = JSArray::kSize + elements_size;
+ int size = JSArray::kSize;
+ int allocation_info_start = size;
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ size += AllocationSiteInfo::kSize;
+ }
+ size += elements_size;
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
@@ -367,6 +373,13 @@
}
__ AllocateInNewSpace(size, r0, r1, r2, fail, flags);
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ mov(r2, Operand(Handle<Map>(masm->isolate()->heap()->
+ allocation_site_info_map())));
+ __ str(r2, FieldMemOperand(r0, allocation_info_start));
+ __ str(r3, FieldMemOperand(r0, allocation_info_start + kPointerSize));
+ }
+
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length == 0)) {
@@ -379,7 +392,11 @@
// Get hold of the elements array of the boilerplate and setup the
// elements pointer in the resulting object.
__ ldr(r3, FieldMemOperand(r3, JSArray::kElementsOffset));
- __ add(r2, r0, Operand(JSArray::kSize));
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ add(r2, r0, Operand(JSArray::kSize + AllocationSiteInfo::kSize));
+ } else {
+ __ add(r2, r0, Operand(JSArray::kSize));
+ }
__ str(r2, FieldMemOperand(r0, JSArray::kElementsOffset));
// Copy the elements array.
@@ -406,6 +423,13 @@
__ b(eq, &slow_case);
FastCloneShallowArrayStub::Mode mode = mode_;
+ AllocationSiteInfoMode allocation_site_info_mode =
+ DONT_TRACK_ALLOCATION_SITE_INFO;
+ if (mode == CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO) {
+ mode = CLONE_ANY_ELEMENTS;
+ allocation_site_info_mode = TRACK_ALLOCATION_SITE_INFO;
+ }
+
if (mode == CLONE_ANY_ELEMENTS) {
Label double_elements, check_fast_elements;
__ ldr(r0, FieldMemOperand(r3, JSArray::kElementsOffset));
@@ -413,7 +437,9 @@
__ CompareRoot(r0, Heap::kFixedCOWArrayMapRootIndex);
__ b(ne, &check_fast_elements);
GenerateFastCloneShallowArrayCommon(masm, 0,
- COPY_ON_WRITE_ELEMENTS, &slow_case);
+ COPY_ON_WRITE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
// Return and remove the on-stack parameters.
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
@@ -422,7 +448,9 @@
__ CompareRoot(r0, Heap::kFixedArrayMapRootIndex);
__ b(ne, &double_elements);
GenerateFastCloneShallowArrayCommon(masm, length_,
- CLONE_ELEMENTS, &slow_case);
+ CLONE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
// Return and remove the on-stack parameters.
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
@@ -454,7 +482,8 @@
__ pop(r3);
}
- GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
+ GenerateFastCloneShallowArrayCommon(masm, length_, mode,
+ allocation_site_info_mode, &slow_case);
// Return and remove the on-stack parameters.
__ add(sp, sp, Operand(3 * kPointerSize));
@@ -560,7 +589,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, RelocInfo::NONE), LeaveCC, ne);
+ __ rsb(source_, source_, Operand::Zero(), 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),
@@ -573,7 +602,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, RelocInfo::NONE));
+ __ mov(mantissa, Operand::Zero());
__ Ret();
__ bind(¬_special);
@@ -1141,7 +1170,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, RelocInfo::NONE), LeaveCC, cs);
+ __ rsb(the_int_, the_int_, Operand::Zero(), 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
@@ -1164,7 +1193,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, RelocInfo::NONE));
+ __ mov(ip, Operand::Zero());
__ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
__ Ret();
}
@@ -1380,7 +1409,7 @@
Operand(lhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord),
SetCC);
__ b(ne, &one_is_nan);
- __ cmp(lhs_mantissa, Operand(0, RelocInfo::NONE));
+ __ cmp(lhs_mantissa, Operand::Zero());
__ b(ne, &one_is_nan);
__ bind(lhs_not_nan);
@@ -1395,7 +1424,7 @@
Operand(rhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord),
SetCC);
__ b(ne, &one_is_nan);
- __ cmp(rhs_mantissa, Operand(0, RelocInfo::NONE));
+ __ cmp(rhs_mantissa, Operand::Zero());
__ b(eq, &neither_is_nan);
__ bind(&one_is_nan);
@@ -1922,7 +1951,7 @@
__ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
__ tst(ip, Operand(1 << Map::kIsUndetectable));
// Undetectable -> false.
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+ __ mov(tos_, Operand::Zero(), LeaveCC, ne);
__ Ret(ne);
}
}
@@ -1955,14 +1984,14 @@
// "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, RelocInfo::NONE), LeaveCC, eq); // for FP_ZERO
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN
+ __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
+ __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
} else {
Label done, not_nan, not_zero;
__ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
// -0 maps to false:
__ bic(
- temp, temp, Operand(HeapNumber::kSignMask, RelocInfo::NONE), SetCC);
+ temp, temp, Operand(HeapNumber::kSignMask, RelocInfo::NONE32), SetCC);
__ b(ne, ¬_zero);
// If exponent word is zero then the answer depends on the mantissa word.
__ ldr(tos_, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
@@ -1975,25 +2004,25 @@
__ mov(temp, Operand(temp, LSR, HeapNumber::kMantissaBitsInTopWord));
unsigned int shifted_exponent_mask =
HeapNumber::kExponentMask >> HeapNumber::kMantissaBitsInTopWord;
- __ cmp(temp, Operand(shifted_exponent_mask, RelocInfo::NONE));
+ __ cmp(temp, Operand(shifted_exponent_mask, RelocInfo::NONE32));
__ b(ne, ¬_nan); // If exponent is not 0x7ff then it can't be a NaN.
// Reload exponent word.
__ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
- __ tst(temp, Operand(HeapNumber::kMantissaMask, RelocInfo::NONE));
+ __ tst(temp, Operand(HeapNumber::kMantissaMask, RelocInfo::NONE32));
// If mantissa is not zero then we have a NaN, so return 0.
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+ __ mov(tos_, Operand::Zero(), LeaveCC, ne);
__ b(ne, &done);
// Load mantissa word.
__ ldr(temp, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
- __ cmp(temp, Operand(0, RelocInfo::NONE));
+ __ cmp(temp, Operand::Zero());
// If mantissa is not zero then we have a NaN, so return 0.
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+ __ mov(tos_, Operand::Zero(), LeaveCC, ne);
__ b(ne, &done);
__ bind(¬_nan);
- __ mov(tos_, Operand(1, RelocInfo::NONE));
+ __ mov(tos_, Operand(1, RelocInfo::NONE32));
__ bind(&done);
}
__ Ret();
@@ -2016,7 +2045,7 @@
// The value of a root is never NULL, so we can avoid loading a non-null
// value into tos_ when we want to return 'true'.
if (!result) {
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq);
+ __ mov(tos_, Operand::Zero(), LeaveCC, eq);
}
__ Ret(eq);
}
@@ -2161,7 +2190,7 @@
__ b(eq, slow);
// Return '0 - value'.
- __ rsb(r0, r0, Operand(0, RelocInfo::NONE));
+ __ rsb(r0, r0, Operand::Zero());
__ Ret();
}
@@ -2429,7 +2458,7 @@
__ cmp(ip, Operand(scratch2));
__ b(ne, ¬_smi_result);
// Go slow on zero result to handle -0.
- __ cmp(scratch1, Operand(0));
+ __ cmp(scratch1, Operand::Zero());
__ mov(right, Operand(scratch1), LeaveCC, ne);
__ Ret(ne);
// We need -0 if we were multiplying a negative number with 0 to get 0.
@@ -2444,7 +2473,7 @@
Label div_with_sdiv;
// Check for 0 divisor.
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
__ b(eq, ¬_smi_result);
// Check for power of two on the right hand side.
@@ -2456,7 +2485,7 @@
__ tst(left, scratch1);
__ b(ne, ¬_smi_result);
// Check for positive left hand side.
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
__ b(mi, &div_with_sdiv);
} else {
__ b(ne, ¬_smi_result);
@@ -2480,12 +2509,12 @@
__ sdiv(scratch1, left, right);
// Check that the remainder is zero.
__ mls(scratch2, scratch1, right, left);
- __ cmp(scratch2, Operand(0));
+ __ cmp(scratch2, Operand::Zero());
__ b(ne, ¬_smi_result);
// Check for negative zero result.
- __ cmp(scratch1, Operand(0));
+ __ cmp(scratch1, Operand::Zero());
__ b(ne, &result_not_zero);
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
__ b(lt, ¬_smi_result);
__ bind(&result_not_zero);
// Check for the corner case of dividing the most negative smi by -1.
@@ -2502,7 +2531,7 @@
if (CpuFeatures::IsSupported(SUDIV)) {
// Check for x % 0.
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
__ b(eq, ¬_smi_result);
// Check for two positive smis.
@@ -2535,10 +2564,10 @@
__ sdiv(scratch1, left, right);
__ mls(right, scratch1, right, left);
// Return if the result is not 0.
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
__ Ret(ne);
// The result is 0, check for -0 case.
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
__ Ret(pl);
// This is a -0 case, restore the value of right.
__ mov(right, scratch2);
@@ -3478,7 +3507,7 @@
__ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
// r0 points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
- __ cmp(cache_entry, Operand(0, RelocInfo::NONE));
+ __ cmp(cache_entry, Operand::Zero());
__ b(eq, &invalid_cache);
#ifdef DEBUG
@@ -3789,8 +3818,8 @@
__ vmov(double_result, 1.0, scratch2);
// Get absolute value of exponent.
- __ cmp(scratch, Operand(0));
- __ mov(scratch2, Operand(0), LeaveCC, mi);
+ __ cmp(scratch, Operand::Zero());
+ __ mov(scratch2, Operand::Zero(), LeaveCC, mi);
__ sub(scratch, scratch2, scratch, LeaveCC, mi);
Label while_true;
@@ -3800,7 +3829,7 @@
__ vmul(double_scratch, double_scratch, double_scratch, ne);
__ b(ne, &while_true);
- __ cmp(exponent, Operand(0));
+ __ cmp(exponent, Operand::Zero());
__ b(ge, &done);
__ vmov(double_scratch, 1.0, scratch);
__ vdiv(double_result, double_scratch, double_result);
@@ -3903,6 +3932,18 @@
}
+static void JumpIfOOM(MacroAssembler* masm,
+ Register value,
+ Register scratch,
+ Label* oom_label) {
+ STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
+ STATIC_ASSERT(kFailureTag == 3);
+ __ and_(scratch, value, Operand(0xf));
+ __ cmp(scratch, Operand(0xf));
+ __ b(eq, oom_label);
+}
+
+
void CEntryStub::GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
Label* throw_termination_exception,
@@ -4002,9 +4043,7 @@
__ b(eq, &retry);
// Special handling of out of memory exceptions.
- Failure* out_of_memory = Failure::OutOfMemoryException();
- __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
- __ b(eq, throw_out_of_memory_exception);
+ JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
__ mov(r3, Operand(isolate->factory()->the_hole_value()));
@@ -4091,13 +4130,16 @@
Isolate* isolate = masm->isolate();
ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
isolate);
- __ mov(r0, Operand(false, RelocInfo::NONE));
+ __ mov(r0, Operand(false, RelocInfo::NONE32));
__ mov(r2, Operand(external_caught));
__ str(r0, MemOperand(r2));
// Set pending exception and r0 to out of memory exception.
- Failure* out_of_memory = Failure::OutOfMemoryException();
+ Label already_have_failure;
+ JumpIfOOM(masm, r0, ip, &already_have_failure);
+ Failure* out_of_memory = Failure::OutOfMemoryException(0x1);
__ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
+ __ bind(&already_have_failure);
__ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ str(r0, MemOperand(r2));
@@ -4773,7 +4815,7 @@
// of the arguments object and the elements array in words.
Label add_arguments_object;
__ bind(&try_allocate);
- __ cmp(r1, Operand(0, RelocInfo::NONE));
+ __ cmp(r1, Operand::Zero());
__ b(eq, &add_arguments_object);
__ mov(r1, Operand(r1, LSR, kSmiTagSize));
__ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize));
@@ -4806,7 +4848,7 @@
// If there are no actual arguments, we're done.
Label done;
- __ cmp(r1, Operand(0, RelocInfo::NONE));
+ __ cmp(r1, Operand::Zero());
__ b(eq, &done);
// Get the parameters pointer from the stack.
@@ -4833,7 +4875,7 @@
// Post-increment r4 with kPointerSize on each iteration.
__ str(r3, MemOperand(r4, kPointerSize, PostIndex));
__ sub(r1, r1, Operand(1));
- __ cmp(r1, Operand(0, RelocInfo::NONE));
+ __ cmp(r1, Operand::Zero());
__ b(ne, &loop);
// Return and remove the on-stack parameters.
@@ -4885,7 +4927,7 @@
ExternalReference::address_of_regexp_stack_memory_size(isolate);
__ mov(r0, Operand(address_of_regexp_stack_memory_size));
__ ldr(r0, MemOperand(r0, 0));
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
__ b(eq, &runtime);
// Check that the first argument is a JSRegExp object.
@@ -4967,7 +5009,7 @@
__ b(gt, &runtime);
// Reset offset for possibly sliced string.
- __ mov(r9, Operand(0));
+ __ mov(r9, Operand::Zero());
// subject: Subject string
// regexp_data: RegExp data (FixedArray)
// Check the representation and encoding of the subject string.
@@ -5088,7 +5130,7 @@
// Argument 6: Set the number of capture registers to zero to force global
// regexps to behave as non-global. This does not affect non-global regexps.
- __ mov(r0, Operand(0));
+ __ mov(r0, Operand::Zero());
__ str(r0, MemOperand(sp, 2 * kPointerSize));
// Argument 5 (sp[4]): static offsets vector buffer.
@@ -5343,7 +5385,7 @@
// r3: Start of elements in FixedArray.
// r5: Number of elements to fill.
Label loop;
- __ cmp(r5, Operand(0));
+ __ cmp(r5, Operand::Zero());
__ bind(&loop);
__ b(le, &done); // Jump if r5 is negative or zero.
__ sub(r5, r5, Operand(1), SetCC);
@@ -5469,8 +5511,8 @@
__ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
__ b(ne, &non_function);
__ push(r1); // put proxy as additional argument
- __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE));
- __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32));
+ __ mov(r2, Operand::Zero());
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
__ SetCallKind(r5, CALL_AS_METHOD);
{
@@ -5484,7 +5526,7 @@
__ bind(&non_function);
__ str(r1, MemOperand(sp, argc_ * kPointerSize));
__ mov(r0, Operand(argc_)); // Set up the number of arguments.
- __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ mov(r2, Operand::Zero());
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(r5, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
@@ -5527,7 +5569,7 @@
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
__ bind(&do_call);
// Set expected number of arguments to zero (not changing r0).
- __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ mov(r2, Operand::Zero());
__ SetCallKind(r5, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
@@ -5632,10 +5674,10 @@
// Fast case of Heap::LookupSingleCharacterStringFromCode.
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiShiftSize == 0);
- ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
+ ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
__ tst(code_,
Operand(kSmiTagMask |
- ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
+ ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
__ b(ne, &slow_case_);
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
@@ -5696,7 +5738,7 @@
if (!ascii) {
__ add(count, count, Operand(count), SetCC);
} else {
- __ cmp(count, Operand(0, RelocInfo::NONE));
+ __ cmp(count, Operand::Zero());
}
__ b(eq, &done);
@@ -5751,7 +5793,7 @@
if (!ascii) {
__ add(count, count, Operand(count), SetCC);
} else {
- __ cmp(count, Operand(0, RelocInfo::NONE));
+ __ cmp(count, Operand::Zero());
}
__ b(eq, &done);
@@ -6274,7 +6316,7 @@
Label compare_chars;
__ bind(&check_zero_length);
STATIC_ASSERT(kSmiTag == 0);
- __ cmp(length, Operand(0));
+ __ cmp(length, Operand::Zero());
__ b(ne, &compare_chars);
__ mov(r0, Operand(Smi::FromInt(EQUAL)));
__ Ret();
@@ -6307,7 +6349,7 @@
__ mov(scratch1, scratch2, LeaveCC, gt);
Register min_length = scratch1;
STATIC_ASSERT(kSmiTag == 0);
- __ cmp(min_length, Operand(0));
+ __ cmp(min_length, Operand::Zero());
__ b(eq, &compare_lengths);
// Compare loop.
@@ -7124,7 +7166,7 @@
__ mov(r1, Operand(Handle<String>(name)));
StringDictionaryLookupStub stub(NEGATIVE_LOOKUP);
__ CallStub(&stub);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
__ ldm(ia_w, sp, spill_mask);
__ b(eq, done);
@@ -7200,7 +7242,7 @@
}
StringDictionaryLookupStub stub(POSITIVE_LOOKUP);
__ CallStub(&stub);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
__ mov(scratch2, Operand(r2));
__ ldm(ia_w, sp, spill_mask);
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 3f1791c..9d00823 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -179,6 +179,10 @@
Label loop, entry, convert_hole, gc_required, only_change_map, done;
bool vfp2_supported = CpuFeatures::IsSupported(VFP2);
+ if (FLAG_track_allocation_sites) {
+ masm->TestJSArrayForAllocationSiteInfo(r2, r4, fail);
+ }
+
// Check for empty arrays, which only require a map transition and no changes
// to the backing store.
__ ldr(r4, FieldMemOperand(r2, JSObject::kElementsOffset));
diff --git a/src/arm/debug-arm.cc b/src/arm/debug-arm.cc
index c2941be..e9a65b2 100644
--- a/src/arm/debug-arm.cc
+++ b/src/arm/debug-arm.cc
@@ -161,7 +161,7 @@
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
- __ mov(r0, Operand(0, RelocInfo::NONE)); // no arguments
+ __ mov(r0, Operand::Zero()); // no arguments
__ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));
CEntryStub ceb(1);
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index a263cb7..55139dd 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -80,12 +80,12 @@
// this is optimized code, so we don't have to have a predictable size.
int call_size_in_bytes =
MacroAssembler::CallSizeNotPredictableCodeSize(deopt_entry,
- RelocInfo::NONE);
+ RelocInfo::NONE32);
int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
ASSERT(call_size_in_bytes <= patch_size());
CodePatcher patcher(call_address, call_size_in_words);
- patcher.masm()->Call(deopt_entry, RelocInfo::NONE);
+ patcher.masm()->Call(deopt_entry, RelocInfo::NONE32);
ASSERT(prev_call_address == NULL ||
call_address >= prev_call_address + patch_size());
ASSERT(call_address + patch_size() <= code->instruction_end());
@@ -458,35 +458,39 @@
// FROM TO <-fp
// | .... | | .... |
// +-------------------------+ +-------------------------+
- // | JSFunction continuation | | JSFunction continuation |
+ // | JSFunction continuation | | parameter 1 |
+ // +-------------------------+ +-------------------------+
+ // | | saved frame (fp) | | .... |
+ // | +=========================+<-fp +-------------------------+
+ // | | JSFunction context | | parameter n |
+ // v +-------------------------+ +-------------------------|
+ // | COMPILED_STUB marker | | JSFunction continuation |
// +-------------------------+ +-------------------------+<-sp
- // | | saved frame (fp) |
- // | +=========================+<-fp
- // | | JSFunction context |
- // v +-------------------------+
- // | COMPILED_STUB marker | fp = saved frame
- // +-------------------------+ f8 = JSFunction context
- // | |
- // | ... |
- // | |
- // +-------------------------+<-sp
+ // | | r0 = number of parameters
+ // | ... | r1 = failure handler address
+ // | | fp = saved frame
+ // +-------------------------+<-sp cp = JSFunction context
//
//
- int output_frame_size = 1 * kPointerSize;
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, 0);
- Code* notify_miss =
- isolate_->builtins()->builtin(Builtins::kNotifyICMiss);
- output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
- output_frame->SetContinuation(
- reinterpret_cast<intptr_t>(notify_miss->entry()));
ASSERT(compiled_code_->kind() == Code::COMPILED_STUB);
int major_key = compiled_code_->major_key();
CodeStubInterfaceDescriptor* descriptor =
isolate_->code_stub_interface_descriptor(major_key);
- Handle<Code> miss_ic(descriptor->deoptimization_handler_);
- output_frame->SetPc(reinterpret_cast<intptr_t>(miss_ic->instruction_start()));
+
+ int output_frame_size =
+ (1 + descriptor->register_param_count_) * kPointerSize;
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, 0);
+ Code* notify_failure =
+ isolate_->builtins()->builtin(Builtins::kNotifyStubFailure);
+ output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
+ output_frame->SetContinuation(
+ reinterpret_cast<uint32_t>(notify_failure->entry()));
+
+ Code* code;
+ CEntryStub(1, kSaveFPRegs).FindCodeInCache(&code, isolate_);
+ output_frame->SetPc(reinterpret_cast<intptr_t>(code->instruction_start()));
unsigned input_frame_size = input_->GetFrameSize();
intptr_t value = input_->GetFrameSlot(input_frame_size - kPointerSize);
output_frame->SetFrameSlot(0, value);
@@ -496,20 +500,23 @@
value = input_->GetFrameSlot(input_frame_size - 3 * kPointerSize);
output_frame->SetRegister(cp.code(), value);
- Translation::Opcode opcode =
- static_cast<Translation::Opcode>(iterator->Next());
- ASSERT(opcode == Translation::REGISTER);
- USE(opcode);
- int input_reg = iterator->Next();
- intptr_t input_value = input_->GetRegister(input_reg);
- output_frame->SetRegister(r1.code(), input_value);
+ int parameter_offset = kPointerSize * descriptor->register_param_count_;
+ for (int i = 0; i < descriptor->register_param_count_; ++i) {
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ ASSERT(opcode == Translation::REGISTER);
+ USE(opcode);
+ int input_reg = iterator->Next();
+ intptr_t reg_value = input_->GetRegister(input_reg);
+ output_frame->SetFrameSlot(parameter_offset, reg_value);
+ parameter_offset -= kPointerSize;
+ }
- int32_t next = iterator->Next();
- opcode = static_cast<Translation::Opcode>(next);
- ASSERT(opcode == Translation::REGISTER);
- input_reg = iterator->Next();
- input_value = input_->GetRegister(input_reg);
- output_frame->SetRegister(r0.code(), input_value);
+ ApiFunction function(descriptor->deoptimization_handler_);
+ ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
+ intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
+ output_frame->SetRegister(r0.code(), descriptor->register_param_count_);
+ output_frame->SetRegister(r1.code(), handler);
ASSERT(frame_index == 0);
output_[frame_index] = output_frame;
@@ -1009,7 +1016,7 @@
// address for lazy deoptimization) and compute the fp-to-sp delta in
// register r4.
if (type() == EAGER) {
- __ mov(r3, Operand(0));
+ __ mov(r3, Operand::Zero());
// Correct one word for bailout id.
__ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
} else if (type() == OSR) {
@@ -1124,7 +1131,7 @@
__ ldr(r7, MemOperand(r6, FrameDescription::frame_content_offset()));
__ push(r7);
__ bind(&inner_loop_header);
- __ cmp(r3, Operand(0));
+ __ cmp(r3, Operand::Zero());
__ b(ne, &inner_push_loop); // test for gt?
__ add(r0, r0, Operand(kPointerSize));
__ bind(&outer_loop_header);
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index b6f3e67..6a97201 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -138,7 +138,7 @@
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
- info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+ info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
__ stop("stop-at");
}
#endif
@@ -149,7 +149,7 @@
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
- __ cmp(r5, Operand(0));
+ __ cmp(r5, Operand::Zero());
__ b(eq, &ok);
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
@@ -1039,7 +1039,7 @@
CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId());
patch_site.EmitPatchInfo();
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
__ b(ne, &next_test);
__ Drop(1); // Switch value is no longer needed.
__ b(clause->body_target());
@@ -1733,6 +1733,15 @@
FastCloneShallowArrayStub::Mode mode = has_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
: FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
+
+ // Tracking allocation info allows us to pre-transition later if it makes
+ // sense.
+ if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS &&
+ FLAG_track_allocation_sites) {
+ mode = FastCloneShallowArrayStub::
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO;
+ }
+
FastCloneShallowArrayStub stub(mode, length);
__ CallStub(&stub);
}
@@ -1991,7 +2000,7 @@
__ mov(ip, Operand(scratch1, ASR, 31));
__ cmp(ip, Operand(scratch2));
__ b(ne, &stub_call);
- __ cmp(scratch1, Operand(0));
+ __ cmp(scratch1, Operand::Zero());
__ mov(right, Operand(scratch1), LeaveCC, ne);
__ b(ne, &done);
__ add(scratch2, right, Operand(left), SetCC);
@@ -2687,7 +2696,7 @@
// Skip loop if no descriptors are valid.
__ NumberOfOwnDescriptors(r3, r1);
- __ cmp(r3, Operand(0));
+ __ cmp(r3, Operand::Zero());
__ b(eq, &done);
__ LoadInstanceDescriptors(r1, r4);
@@ -3018,7 +3027,7 @@
// Move 0x41300000xxxxxxxx (x = random bits) to VFP.
__ vmov(d7, r0, r1);
// Move 0x4130000000000000 to VFP.
- __ mov(r0, Operand(0, RelocInfo::NONE));
+ __ mov(r0, Operand::Zero());
__ vmov(d8, r0, r1);
// Subtract and store the result in the heap number.
__ vsub(d7, d7, d8);
@@ -3634,7 +3643,7 @@
// Check that all array elements are sequential ASCII strings, and
// accumulate the sum of their lengths, as a smi-encoded value.
- __ mov(string_length, Operand(0));
+ __ mov(string_length, Operand::Zero());
__ add(element,
elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
@@ -3647,7 +3656,7 @@
// element: Current array element.
// elements_end: Array end.
if (generate_debug_code_) {
- __ cmp(array_length, Operand(0));
+ __ cmp(array_length, Operand::Zero());
__ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin");
}
__ bind(&loop);
@@ -3690,7 +3699,7 @@
__ smull(scratch2, ip, array_length, scratch1);
// Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
// zero.
- __ cmp(ip, Operand(0));
+ __ cmp(ip, Operand::Zero());
__ b(ne, &bailout);
__ tst(scratch2, Operand(0x80000000));
__ b(ne, &bailout);
@@ -4357,7 +4366,7 @@
CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId());
patch_site.EmitPatchInfo();
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
Split(cond, if_true, if_false, fall_through);
}
}
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 29a3687..5e17694 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -862,7 +862,7 @@
__ mov(r0, r2);
__ Ret();
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -891,7 +891,7 @@
__ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
__ Ret();
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -925,7 +925,7 @@
Object* KeyedLoadIC_Miss(Arguments args);
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
@@ -938,7 +938,7 @@
__ Push(r1, r0);
// Perform tail call to the entry.
- ExternalReference ref = force_generic
+ ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
: ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
@@ -1158,7 +1158,7 @@
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -1198,11 +1198,11 @@
1);
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
@@ -1213,7 +1213,7 @@
// Push receiver, key and value for runtime call.
__ Push(r2, r1, r0);
- ExternalReference ref = force_generic
+ ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index e2a0f2d..c7fe06c 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -121,7 +121,7 @@
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
- info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+ info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
__ stop("stop_at");
}
#endif
@@ -137,7 +137,7 @@
// function calls.
if (!info_->is_classic_mode() || info_->is_native()) {
Label ok;
- __ cmp(r5, Operand(0));
+ __ cmp(r5, Operand::Zero());
__ b(eq, &ok);
int receiver_offset = scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
@@ -524,11 +524,11 @@
return Operand(ToRegister(op));
} else if (op->IsDoubleRegister()) {
Abort("ToOperand IsDoubleRegister unimplemented");
- return Operand(0);
+ return Operand::Zero();
}
// Stack slots not implemented, use ToMemOperand instead.
UNREACHABLE();
- return Operand(0);
+ return Operand::Zero();
}
@@ -1076,14 +1076,14 @@
if (divisor < 0) divisor = -divisor;
Label positive_dividend, done;
- __ cmp(dividend, Operand(0));
+ __ cmp(dividend, Operand::Zero());
__ b(pl, &positive_dividend);
- __ rsb(result, dividend, Operand(0));
+ __ rsb(result, dividend, Operand::Zero());
__ and_(result, result, Operand(divisor - 1), SetCC);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment());
}
- __ rsb(result, result, Operand(0));
+ __ rsb(result, result, Operand::Zero());
__ b(&done);
__ bind(&positive_dividend);
__ and_(result, dividend, Operand(divisor - 1));
@@ -1101,7 +1101,7 @@
CpuFeatures::Scope scope(SUDIV);
// Check for x % 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
@@ -1121,11 +1121,11 @@
__ sdiv(result, left, right);
__ mls(result, result, right, left);
- __ cmp(result, Operand(0));
+ __ cmp(result, Operand::Zero());
__ b(ne, &done);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
DeoptimizeIf(lt, instr->environment());
}
} else {
@@ -1148,14 +1148,14 @@
// Check for x % 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
__ Move(result, left);
// (0 % x) must yield 0 (if x is finite, which is the case here).
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
__ b(eq, &done);
// Preload right in a vfp register.
__ vmov(divisor.low(), right);
@@ -1175,7 +1175,7 @@
__ bind(&right_negative);
// Negate right. The sign of the divisor does not matter.
- __ rsb(right, right, Operand(0));
+ __ rsb(right, right, Operand::Zero());
__ bind(&both_positive);
const int kUnfolds = 3;
@@ -1226,7 +1226,7 @@
// Check for -0.
__ sub(scratch2, left, scratch, SetCC);
__ b(ne, &ok);
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
DeoptimizeIf(mi, instr->environment());
__ bind(&ok);
// Load the result and we are done.
@@ -1261,11 +1261,11 @@
if (divisor > 0) {
__ Move(result, dividend);
} else {
- __ rsb(result, dividend, Operand(0), SetCC);
+ __ rsb(result, dividend, Operand::Zero(), SetCC);
DeoptimizeIf(vs, environment);
}
// Compute the remainder.
- __ mov(remainder, Operand(0));
+ __ mov(remainder, Operand::Zero());
return;
default:
@@ -1283,7 +1283,7 @@
// handled separately.
if (divisor < 0) {
ASSERT(divisor != -1);
- __ rsb(result, result, Operand(0));
+ __ rsb(result, result, Operand::Zero());
}
// Compute the remainder.
if (divisor > 0) {
@@ -1319,7 +1319,7 @@
__ mov(scratch, Operand(scratch, ASR, s));
}
__ add(result, scratch, Operand(dividend, LSR, 31));
- if (divisor < 0) __ rsb(result, result, Operand(0));
+ if (divisor < 0) __ rsb(result, result, Operand::Zero());
// Compute the remainder.
__ mov(ip, Operand(divisor));
// This sequence could be replaced with 'mls' when
@@ -1354,16 +1354,16 @@
// Check for x / 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label left_not_zero;
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
__ b(ne, &left_not_zero);
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
DeoptimizeIf(mi, instr->environment());
__ bind(&left_not_zero);
}
@@ -1441,7 +1441,7 @@
int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
if (divisor < 0) {
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
EmitSignedIntegerDivisionByConstant(result,
@@ -1451,7 +1451,7 @@
scratch,
instr->environment());
// We performed a truncating division. Correct the result if necessary.
- __ cmp(remainder, Operand(0));
+ __ cmp(remainder, Operand::Zero());
__ teq(remainder, Operand(divisor), ne);
__ sub(result, result, Operand(1), LeaveCC, mi);
} else {
@@ -1459,7 +1459,7 @@
const Register right = ToRegister(instr->right());
// Check for x / 0.
- __ cmp(right, Operand(0));
+ __ cmp(right, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
// Check for (kMinInt / -1).
@@ -1474,8 +1474,8 @@
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- __ cmp(right, Operand(0));
- __ cmp(left, Operand(0), mi);
+ __ cmp(right, Operand::Zero());
+ __ cmp(left, Operand::Zero(), mi);
// "right" can't be null because the code would have already been
// deoptimized. The Z flag is set only if (right < 0) and (left == 0).
// In this case we need to deoptimize to produce a -0.
@@ -1490,7 +1490,7 @@
// Check if the result needs to be corrected.
__ mls(remainder, result, right, left);
- __ cmp(remainder, Operand(0));
+ __ cmp(remainder, Operand::Zero());
__ sub(result, result, Operand(1), LeaveCC, ne);
__ bind(&done);
@@ -1549,22 +1549,22 @@
if (bailout_on_minus_zero && (constant < 0)) {
// The case of a null constant will be handled separately.
// If constant is negative and left is null, the result should be -0.
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
switch (constant) {
case -1:
- __ rsb(result, left, Operand(0));
+ __ rsb(result, left, Operand::Zero());
break;
case 0:
if (bailout_on_minus_zero) {
// If left is strictly negative and the constant is null, the
// result is -0. Deoptimize if required, otherwise return 0.
- __ cmp(left, Operand(0));
+ __ cmp(left, Operand::Zero());
DeoptimizeIf(mi, instr->environment());
}
- __ mov(result, Operand(0));
+ __ mov(result, Operand::Zero());
break;
case 1:
__ Move(result, left);
@@ -1591,7 +1591,7 @@
}
// Correct the sign of the result is the constant is negative.
- if (constant < 0) __ rsb(result, result, Operand(0));
+ if (constant < 0) __ rsb(result, result, Operand::Zero());
} else {
// Generate standard code.
@@ -1618,9 +1618,9 @@
if (bailout_on_minus_zero) {
// Bail out if the result is supposed to be negative zero.
Label done;
- __ cmp(result, Operand(0));
+ __ cmp(result, Operand::Zero());
__ b(ne, &done);
- __ cmp(ToRegister(instr->temp()), Operand(0));
+ __ cmp(ToRegister(instr->temp()), Operand::Zero());
DeoptimizeIf(mi, instr->environment());
__ bind(&done);
}
@@ -2100,7 +2100,7 @@
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32()) {
Register reg = ToRegister(instr->value());
- __ cmp(reg, Operand(0));
+ __ cmp(reg, Operand::Zero());
EmitBranch(true_block, false_block, ne);
} else if (r.IsDouble()) {
CpuFeatures::Scope scope(VFP2);
@@ -2119,7 +2119,7 @@
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
EmitBranch(true_block, false_block, eq);
} else if (type.IsSmi()) {
- __ cmp(reg, Operand(0));
+ __ cmp(reg, Operand::Zero());
EmitBranch(true_block, false_block, ne);
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
@@ -2149,7 +2149,7 @@
if (expected.Contains(ToBooleanStub::SMI)) {
// Smis: 0 -> false, all other -> true.
- __ cmp(reg, Operand(0));
+ __ cmp(reg, Operand::Zero());
__ b(eq, false_label);
__ JumpIfSmi(reg, true_label);
} else if (expected.NeedsMap()) {
@@ -2182,7 +2182,7 @@
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
__ b(ge, ¬_string);
__ ldr(ip, FieldMemOperand(reg, String::kLengthOffset));
- __ cmp(ip, Operand(0));
+ __ cmp(ip, Operand::Zero());
__ b(ne, true_label);
__ b(false_label);
__ bind(¬_string);
@@ -2477,7 +2477,8 @@
Handle<Code> ic = CompareIC::GetUninitialized(op);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
- __ cmp(r0, Operand(0)); // This instruction also signals no smi code inlined.
+ // This instruction also signals no smi code inlined.
+ __ cmp(r0, Operand::Zero());
Condition condition = ComputeCompareCondition(op);
@@ -2561,7 +2562,7 @@
__ JumpIfSmi(input, is_false);
- if (class_name->IsEqualTo(CStrVector("Function"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
// Assuming the following assertions, we can use the same compares to test
// for both being a function type and being in the object type range.
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
@@ -2592,7 +2593,7 @@
// Objects with a non-function constructor have class 'Object'.
__ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE);
- if (class_name->IsEqualTo(CStrVector("Object"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
__ b(ne, is_true);
} else {
__ b(ne, is_false);
@@ -2651,7 +2652,7 @@
InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
__ mov(r0, Operand(factory()->false_value()), LeaveCC, ne);
__ mov(r0, Operand(factory()->true_value()), LeaveCC, eq);
}
@@ -2795,7 +2796,8 @@
Handle<Code> ic = CompareIC::GetUninitialized(op);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
- __ cmp(r0, Operand(0)); // This instruction also signals no smi code inlined.
+ // This instruction also signals no smi code inlined.
+ __ cmp(r0, Operand::Zero());
Condition condition = ComputeCompareCondition(op);
__ LoadRoot(ToRegister(instr->result()),
@@ -3535,7 +3537,7 @@
// stack.
Label invoke, loop;
// length is a small non-negative integer, due to the test above.
- __ cmp(length, Operand(0));
+ __ cmp(length, Operand::Zero());
__ b(eq, &invoke);
__ bind(&loop);
__ ldr(scratch, MemOperand(elements, length, LSL, 2));
@@ -3739,12 +3741,12 @@
void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
- __ cmp(input, Operand(0));
+ __ cmp(input, Operand::Zero());
__ Move(result, input, pl);
// We can make rsb conditional because the previous cmp instruction
// will clear the V (overflow) flag and rsb won't set this flag
// if input is positive.
- __ rsb(result, input, Operand(0), SetCC, mi);
+ __ rsb(result, input, Operand::Zero(), SetCC, mi);
// Deoptimize on overflow.
DeoptimizeIf(vs, instr->environment());
}
@@ -3803,7 +3805,7 @@
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0.
Label done;
- __ cmp(result, Operand(0));
+ __ cmp(result, Operand::Zero());
__ b(ne, &done);
__ vmov(scratch, input.high());
__ tst(scratch, Operand(HeapNumber::kSignMask));
@@ -3830,7 +3832,7 @@
// If the number is in ]-0.5, +0.5[, the result is +/- 0.
__ cmp(scratch, Operand(HeapNumber::kExponentBias - 2));
- __ mov(result, Operand(0), LeaveCC, le);
+ __ mov(result, Operand::Zero(), LeaveCC, le);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ b(le, &check_sign_on_zero);
} else {
@@ -3855,7 +3857,7 @@
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(mi, instr->environment());
} else {
- __ mov(result, Operand(0), LeaveCC, mi);
+ __ mov(result, Operand::Zero(), LeaveCC, mi);
__ b(mi, &done);
}
@@ -3868,7 +3870,7 @@
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0.
- __ cmp(result, Operand(0));
+ __ cmp(result, Operand::Zero());
__ b(ne, &done);
__ bind(&check_sign_on_zero);
__ vmov(scratch, input.high());
@@ -3972,7 +3974,7 @@
// Load state[0].
__ ldr(r1, FieldMemOperand(r2, ByteArray::kHeaderSize));
- __ cmp(r1, Operand(0));
+ __ cmp(r1, Operand::Zero());
__ b(eq, deferred->entry());
// Load state[1].
__ ldr(r0, FieldMemOperand(r2, ByteArray::kHeaderSize + kSeedSize));
@@ -4007,7 +4009,7 @@
// Move 0x41300000xxxxxxxx (x = random bits) to VFP.
__ vmov(d7, r0, r1);
// Move 0x4130000000000000 to VFP.
- __ mov(r0, Operand(0, RelocInfo::NONE));
+ __ mov(r0, Operand::Zero());
__ vmov(d8, r0, r1);
// Subtract and store the result in the heap number.
__ vsub(d7, d7, d8);
@@ -4582,7 +4584,7 @@
// TODO(3095996): Get rid of this. For now, we need to make the
// result register contain a valid pointer because it is already
// contained in the register pointer map.
- __ mov(result, Operand(0));
+ __ mov(result, Operand::Zero());
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ push(string);
@@ -4623,7 +4625,7 @@
Register result = ToRegister(instr->result());
ASSERT(!char_code.is(result));
- __ cmp(char_code, Operand(String::kMaxAsciiCharCode));
+ __ cmp(char_code, Operand(String::kMaxOneByteCharCode));
__ b(hi, deferred->entry());
__ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
__ add(result, result, Operand(char_code, LSL, kPointerSizeLog2));
@@ -4642,7 +4644,7 @@
// TODO(3095996): Get rid of this. For now, we need to make the
// result register contain a valid pointer because it is already
// contained in the register pointer map.
- __ mov(result, Operand(0));
+ __ mov(result, Operand::Zero());
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ SmiTag(char_code);
@@ -4763,7 +4765,7 @@
masm->orr(hiword, scratch,
Operand(hiword, LSR, mantissa_shift_for_hi_word));
} else {
- masm->mov(loword, Operand(0, RelocInfo::NONE));
+ masm->mov(loword, Operand::Zero());
masm->orr(hiword, scratch,
Operand(hiword, LSL, -mantissa_shift_for_hi_word));
}
@@ -4841,7 +4843,7 @@
// TODO(3095996): Put a valid pointer value in the stack slot where the result
// register is stored, as this register is in the pointer map, but contains an
// integer value.
- __ mov(ip, Operand(0));
+ __ mov(ip, Operand::Zero());
__ StoreToSafepointRegisterSlot(ip, dst);
CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
__ Move(dst, r0);
@@ -4906,7 +4908,7 @@
// result register contain a valid pointer because it is already
// contained in the register pointer map.
Register reg = ToRegister(instr->result());
- __ mov(reg, Operand(0));
+ __ mov(reg, Operand::Zero());
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
@@ -4977,7 +4979,7 @@
__ vldr(result_reg, ip, HeapNumber::kValueOffset);
if (deoptimize_on_minus_zero) {
__ vmov(ip, result_reg.low());
- __ cmp(ip, Operand(0));
+ __ cmp(ip, Operand::Zero());
__ b(ne, &done);
__ vmov(ip, result_reg.high());
__ cmp(ip, Operand(HeapNumber::kSignMask));
@@ -5032,7 +5034,7 @@
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(input_reg, Operand(ip));
DeoptimizeIf(ne, instr->environment());
- __ mov(input_reg, Operand(0));
+ __ mov(input_reg, Operand::Zero());
__ b(&done);
__ bind(&heap_number);
@@ -5062,7 +5064,7 @@
DeoptimizeIf(ne, instr->environment());
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- __ cmp(input_reg, Operand(0));
+ __ cmp(input_reg, Operand::Zero());
__ b(ne, &done);
__ vmov(scratch1, double_scratch.high());
__ tst(scratch1, Operand(HeapNumber::kSignMask));
@@ -5293,7 +5295,7 @@
// conversions.
__ cmp(input_reg, Operand(factory()->undefined_value()));
DeoptimizeIf(ne, instr->environment());
- __ mov(result_reg, Operand(0));
+ __ mov(result_reg, Operand::Zero());
__ jmp(&done);
// Heap number
@@ -5415,7 +5417,7 @@
// TODO(3095996): Get rid of this. For now, we need to make the
// result register contain a valid pointer because it is already
// contained in the register pointer map.
- __ mov(result, Operand(0));
+ __ mov(result, Operand::Zero());
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ mov(r0, Operand(Smi::FromInt(instance_size)));
@@ -6044,7 +6046,7 @@
FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
__ ldr(result,
FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
- __ cmp(result, Operand(0));
+ __ cmp(result, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
__ bind(&done);
@@ -6067,7 +6069,7 @@
Register scratch = scratch0();
Label out_of_object, done;
- __ cmp(index, Operand(0));
+ __ cmp(index, Operand::Zero());
__ b(lt, &out_of_object);
STATIC_ASSERT(kPointerSizeLog2 > kSmiTagSize);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 0764e09..d7ea107 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -304,7 +304,7 @@
if (!src2.is_reg() &&
!src2.must_output_reloc_info(this) &&
src2.immediate() == 0) {
- mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, cond);
+ mov(dst, Operand::Zero(), LeaveCC, cond);
} else if (!src2.is_single_instruction(this) &&
!src2.must_output_reloc_info(this) &&
CpuFeatures::IsSupported(ARMv7) &&
@@ -410,7 +410,7 @@
}
tst(dst, Operand(~satval));
b(eq, &done);
- mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, mi); // 0 if negative.
+ mov(dst, Operand::Zero(), LeaveCC, mi); // 0 if negative.
mov(dst, Operand(satval), LeaveCC, pl); // satval if positive.
bind(&done);
} else {
@@ -864,7 +864,7 @@
// Reserve room for saved entry sp and code object.
sub(sp, sp, Operand(2 * kPointerSize));
if (emit_debug_code()) {
- mov(ip, Operand(0));
+ mov(ip, Operand::Zero());
str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
}
mov(ip, Operand(CodeObject()));
@@ -948,7 +948,7 @@
}
// Clear top frame.
- mov(r3, Operand(0, RelocInfo::NONE));
+ mov(r3, Operand::Zero());
mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
str(r3, MemOperand(ip));
@@ -1218,7 +1218,7 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() {
- mov(r0, Operand(0, RelocInfo::NONE));
+ mov(r0, Operand::Zero());
mov(r1, Operand(ExternalReference(Runtime::kDebugBreak, isolate())));
CEntryStub ces(1);
ASSERT(AllowThisStubCall(&ces));
@@ -1249,7 +1249,7 @@
// Push the frame pointer, context, state, and code object.
if (kind == StackHandler::JS_ENTRY) {
mov(r7, Operand(Smi::FromInt(0))); // Indicates no context.
- mov(ip, Operand(0, RelocInfo::NONE)); // NULL frame pointer.
+ mov(ip, Operand::Zero()); // NULL frame pointer.
stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | ip.bit());
} else {
stm(db_w, sp, r5.bit() | r6.bit() | cp.bit() | fp.bit());
@@ -1373,7 +1373,7 @@
ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
// In debug mode, make sure the lexical context is set.
#ifdef DEBUG
- cmp(scratch, Operand(0, RelocInfo::NONE));
+ cmp(scratch, Operand::Zero());
Check(ne, "we should not have an empty lexical context");
#endif
@@ -2025,7 +2025,7 @@
// it's an Infinity, and the non-NaN code path applies.
b(gt, &is_nan);
ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
- cmp(mantissa_reg, Operand(0));
+ cmp(mantissa_reg, Operand::Zero());
b(eq, &have_double_value);
bind(&is_nan);
// Load canonical NaN for storing into the double array.
@@ -2277,7 +2277,7 @@
// If result is non-zero, dereference to get the result value
// otherwise set it to undefined.
- cmp(r0, Operand(0));
+ cmp(r0, Operand::Zero());
LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
ldr(r0, MemOperand(r0), ne);
@@ -2456,7 +2456,7 @@
HeapNumber::kExponentBits);
// Load dest with zero. We use this either for the final shift or
// for the answer.
- mov(dest, Operand(0, RelocInfo::NONE));
+ mov(dest, Operand::Zero());
// 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
@@ -2510,7 +2510,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, RelocInfo::NONE), LeaveCC, ne);
+ rsb(dest, dest, Operand::Zero(), LeaveCC, ne);
bind(&done);
}
}
@@ -2601,7 +2601,7 @@
// Check for Infinity and NaNs, which should return 0.
cmp(result, Operand(HeapNumber::kExponentMask));
- mov(result, Operand(0), LeaveCC, eq);
+ mov(result, Operand::Zero(), LeaveCC, eq);
b(eq, &done);
// Express exponent as delta to (number of mantissa bits + 31).
@@ -2613,7 +2613,7 @@
// If the delta is strictly positive, all bits would be shifted away,
// which means that we can return 0.
b(le, &normal_exponent);
- mov(result, Operand(0));
+ mov(result, Operand::Zero());
b(&done);
bind(&normal_exponent);
@@ -2641,7 +2641,7 @@
b(&pos_shift, ge);
// Negate scratch.
- rsb(scratch, scratch, Operand(0));
+ rsb(scratch, scratch, Operand::Zero());
mov(input_low, Operand(input_low, LSL, scratch));
b(&shift_done);
@@ -2651,10 +2651,10 @@
bind(&shift_done);
orr(input_high, input_high, Operand(input_low));
// Restore sign if necessary.
- cmp(sign, Operand(0));
+ cmp(sign, Operand::Zero());
result = sign;
sign = no_reg;
- rsb(result, input_high, Operand(0), LeaveCC, ne);
+ rsb(result, input_high, Operand::Zero(), LeaveCC, ne);
mov(result, input_high, LeaveCC, eq);
bind(&done);
}
@@ -3295,7 +3295,7 @@
// Align src before copying in word size chunks.
bind(&align_loop);
- cmp(length, Operand(0));
+ cmp(length, Operand::Zero());
b(eq, &done);
bind(&align_loop_1);
tst(src, Operand(kPointerSize - 1));
@@ -3330,7 +3330,7 @@
// Copy the last bytes if any left.
bind(&byte_loop);
- cmp(length, Operand(0));
+ cmp(length, Operand::Zero());
b(eq, &done);
bind(&byte_loop_1);
ldrb(scratch, MemOperand(src, 1, PostIndex));
@@ -3368,7 +3368,7 @@
// Order of the next two lines is important: zeros register
// can be the same as source register.
Move(scratch, source);
- mov(zeros, Operand(0, RelocInfo::NONE));
+ mov(zeros, Operand::Zero());
// Top 16.
tst(scratch, Operand(0xffff0000));
add(zeros, zeros, Operand(16), LeaveCC, eq);
@@ -3800,7 +3800,7 @@
b(gt, &above_zero);
// Double value is less than zero, NaN or Inf, return 0.
- mov(result_reg, Operand(0));
+ mov(result_reg, Operand::Zero());
b(al, &done);
// Double value is >= 255, return 255.
@@ -3883,6 +3883,29 @@
}
+void MacroAssembler::TestJSArrayForAllocationSiteInfo(
+ Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present) {
+ Label no_info_available;
+ ExternalReference new_space_start =
+ ExternalReference::new_space_start(isolate());
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+ ldr(scratch_reg, FieldMemOperand(receiver_reg,
+ JSArray::kSize + AllocationSiteInfo::kSize));
+ cmp(scratch_reg, Operand(new_space_start));
+ b(lt, &no_info_available);
+ cmp(scratch_reg, Operand(new_space_allocation_top));
+ b(hs, &no_info_available);
+ ldr(scratch_reg, MemOperand(scratch_reg, 0));
+ cmp(scratch_reg,
+ Operand(Handle<Map>(isolate()->heap()->allocation_site_info_map())));
+ b(eq, allocation_info_present);
+ bind(&no_info_available);
+}
+
+
#ifdef DEBUG
bool AreAliased(Register reg1,
Register reg2,
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 454e645..d1b94cd 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -1309,6 +1309,16 @@
// in r0. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Register null_value, Label* call_runtime);
+ // AllocationSiteInfo support. Arrays may have an associated
+ // AllocationSiteInfo object that can be checked for in order to pretransition
+ // to another type.
+ // On entry, receiver_reg should point to the array object.
+ // scratch_reg gets clobbered.
+ // If allocation info is present, jump to allocation_info_present
+ void TestJSArrayForAllocationSiteInfo(Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present);
+
private:
void CallCFunctionHelper(Register function,
int num_reg_arguments,
diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
index d852d23..acb24ef 100644
--- a/src/arm/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -204,7 +204,7 @@
Label not_at_start;
// Did we start the match at the start of the string at all?
__ ldr(r0, MemOperand(frame_pointer(), kStartIndex));
- __ cmp(r0, Operand(0, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
BranchOrBacktrack(ne, ¬_at_start);
// If we did, are we still at the start of the input?
@@ -219,7 +219,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(), kStartIndex));
- __ cmp(r0, Operand(0, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
BranchOrBacktrack(ne, on_not_at_start);
// If we did, are we still at the start of the input?
__ ldr(r1, MemOperand(frame_pointer(), kInputStart));
@@ -261,7 +261,7 @@
for (int i = 0; i < str.length(); i++) {
if (mode_ == ASCII) {
__ ldrb(r1, MemOperand(r0, char_size(), PostIndex));
- ASSERT(str[i] <= String::kMaxAsciiCharCode);
+ ASSERT(str[i] <= String::kMaxOneByteCharCode);
__ cmp(r1, Operand(str[i]));
} else {
__ ldrh(r1, MemOperand(r0, char_size(), PostIndex));
@@ -337,8 +337,17 @@
__ b(ne, &fail);
__ sub(r3, r3, Operand('a'));
__ cmp(r3, Operand('z' - 'a')); // Is r3 a lowercase letter?
+#ifndef ENABLE_LATIN_1
__ b(hi, &fail);
-
+#else
+ __ b(ls, &loop_check); // In range 'a'-'z'.
+ // Latin-1: Check for values in range [224,254] but not 247.
+ __ sub(r3, r3, Operand(224 - 'a'));
+ __ cmp(r3, Operand(254 - 224));
+ __ b(hi, &fail); // Weren't Latin-1 letters.
+ __ cmp(r3, Operand(247 - 224)); // Check for 247.
+ __ b(eq, &fail);
+#endif
__ bind(&loop_check);
__ cmp(r0, r1);
@@ -385,7 +394,7 @@
}
// Check if function returned non-zero for success or zero for failure.
- __ cmp(r0, Operand(0, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
BranchOrBacktrack(eq, on_no_match);
// On success, increment position by length of capture.
__ add(current_input_offset(), current_input_offset(), Operand(r4));
@@ -508,7 +517,7 @@
Handle<ByteArray> table,
Label* on_bit_set) {
__ mov(r0, Operand(table));
- if (mode_ != ASCII || kTableMask != String::kMaxAsciiCharCode) {
+ if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) {
__ and_(r1, current_character(), Operand(kTableSize - 1));
__ add(r1, r1, Operand(ByteArray::kHeaderSize - kHeapObjectTag));
} else {
@@ -517,7 +526,7 @@
Operand(ByteArray::kHeaderSize - kHeapObjectTag));
}
__ ldrb(r0, MemOperand(r0, r1));
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
BranchOrBacktrack(ne, on_bit_set);
}
@@ -613,7 +622,7 @@
ExternalReference map = ExternalReference::re_word_character_map();
__ mov(r0, Operand(map));
__ ldrb(r0, MemOperand(r0, current_character()));
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
BranchOrBacktrack(eq, on_no_match);
return true;
}
@@ -627,7 +636,7 @@
ExternalReference map = ExternalReference::re_word_character_map();
__ mov(r0, Operand(map));
__ ldrb(r0, MemOperand(r0, current_character()));
- __ cmp(r0, Operand(0));
+ __ cmp(r0, Operand::Zero());
BranchOrBacktrack(ne, on_no_match);
if (mode_ != ASCII) {
__ bind(&done);
@@ -675,7 +684,7 @@
// Set frame pointer in space for it if this is not a direct call
// from generated code.
__ add(frame_pointer(), sp, Operand(4 * kPointerSize));
- __ mov(r0, Operand(0, RelocInfo::NONE));
+ __ mov(r0, Operand::Zero());
__ push(r0); // Make room for success counter and initialize it to 0.
__ push(r0); // Make room for "position - 1" constant (value is irrelevant).
// Check if we have space on the stack for registers.
@@ -700,7 +709,7 @@
__ bind(&stack_limit_hit);
CallCheckStackGuardState(r0);
- __ cmp(r0, Operand(0, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
// If returned value is non-zero, we exit with the returned value as result.
__ b(ne, &return_r0);
@@ -728,7 +737,7 @@
Label load_char_start_regexp, start_regexp;
// Load newline if index is at start, previous character otherwise.
- __ cmp(r1, Operand(0, RelocInfo::NONE));
+ __ cmp(r1, Operand::Zero());
__ b(ne, &load_char_start_regexp);
__ mov(current_character(), Operand('\n'), LeaveCC, eq);
__ jmp(&start_regexp);
@@ -834,7 +843,7 @@
// Not a zero-length match, restart.
__ b(ne, &load_char_start_regexp);
// Offset from the end is zero if we already reached the end.
- __ cmp(current_input_offset(), Operand(0));
+ __ cmp(current_input_offset(), Operand::Zero());
__ b(eq, &exit_label_);
// Advance current position after a zero-length match.
__ add(current_input_offset(),
@@ -873,7 +882,7 @@
SafeCallTarget(&check_preempt_label_);
CallCheckStackGuardState(r0);
- __ cmp(r0, Operand(0, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
// If returning non-zero, we should end execution with the given
// result as return value.
__ b(ne, &return_r0);
@@ -900,7 +909,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, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
__ b(eq, &exit_with_exception);
// Otherwise use return value as new stack pointer.
__ mov(backtrack_stackpointer(), r0);
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index d11e340..c143cc5 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -1776,7 +1776,7 @@
if (::v8::internal::FLAG_trace_sim) {
PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
}
- set_register(r0, (int32_t) *result);
+ set_register(r0, reinterpret_cast<int32_t>(*result));
} else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
SimulatorRuntimeDirectGetterCall target =
reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
@@ -1793,7 +1793,7 @@
if (::v8::internal::FLAG_trace_sim) {
PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
}
- set_register(r0, (int32_t) *result);
+ set_register(r0, reinterpret_cast<int32_t>(*result));
} else {
// builtin call.
ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
@@ -3083,15 +3083,15 @@
if (src_precision == kDoublePrecision) {
if (unsigned_integer) {
- set_d_register_from_double(dst,
- static_cast<double>((uint32_t)val));
+ set_d_register_from_double(
+ dst, static_cast<double>(static_cast<uint32_t>(val)));
} else {
set_d_register_from_double(dst, static_cast<double>(val));
}
} else {
if (unsigned_integer) {
- set_s_register_from_float(dst,
- static_cast<float>((uint32_t)val));
+ set_s_register_from_float(
+ dst, static_cast<float>(static_cast<uint32_t>(val)));
} else {
set_s_register_from_float(dst, static_cast<float>(val));
}
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index dd5db30..dcc88f7 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -735,7 +735,7 @@
__ mov(ip, Operand(argc));
__ str(ip, MemOperand(r0, 2 * kPointerSize));
// v8::Arguments::is_construct_call = 0
- __ mov(ip, Operand(0));
+ __ mov(ip, Operand::Zero());
__ str(ip, MemOperand(r0, 3 * kPointerSize));
const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
@@ -1008,7 +1008,7 @@
__ and_(fval, ival, Operand(kBinary32SignMask), SetCC);
// Negate value if it is negative.
- __ rsb(ival, ival, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+ __ rsb(ival, ival, Operand::Zero(), 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),
@@ -2241,7 +2241,7 @@
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
// Check for -0.
- __ cmp(r0, Operand(0, RelocInfo::NONE));
+ __ cmp(r0, Operand::Zero());
__ b(&restore_fpscr_and_return, ne);
// r5 already holds the HeapNumber exponent.
__ tst(r5, Operand(HeapNumber::kSignMask));
@@ -3327,7 +3327,7 @@
__ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
+ return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
}
@@ -3431,7 +3431,7 @@
__ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
+ return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
}
@@ -3944,18 +3944,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, RelocInfo::NONE), LeaveCC, eq);
+ __ mov(r5, Operand::Zero(), LeaveCC, eq);
__ b(eq, &done);
__ teq(r9, Operand(r7));
- __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
+ __ mov(r5, Operand::Zero(), 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 then result is 0.
- __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, mi);
+ __ mov(r5, Operand::Zero(), LeaveCC, mi);
__ b(mi, &done);
// If exponent is too big then result is minimal value.
@@ -3971,14 +3971,14 @@
__ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
__ b(pl, &sign);
- __ rsb(r9, r9, Operand(0, RelocInfo::NONE));
+ __ rsb(r9, r9, Operand::Zero());
__ 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, RelocInfo::NONE));
- __ rsb(r5, r5, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+ __ teq(r7, Operand::Zero());
+ __ rsb(r5, r5, Operand::Zero(), LeaveCC, ne);
__ bind(&done);
switch (elements_kind) {
diff --git a/src/assembler.cc b/src/assembler.cc
index f1d5de1..e284974 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -692,7 +692,7 @@
#ifdef ENABLE_DISASSEMBLER
const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
switch (rmode) {
- case RelocInfo::NONE:
+ case RelocInfo::NONE32:
return "no reloc 32";
case RelocInfo::NONE64:
return "no reloc 64";
@@ -818,7 +818,7 @@
case INTERNAL_REFERENCE:
case CONST_POOL:
case DEBUG_BREAK_SLOT:
- case NONE:
+ case NONE32:
case NONE64:
break;
case NUMBER_OF_MODES:
@@ -1403,7 +1403,8 @@
double power_double_double(double x, double y) {
-#ifdef __MINGW64_VERSION_MAJOR
+#if defined(__MINGW64_VERSION_MAJOR) && \
+ (!defined(__MINGW64_VERSION_RC) || __MINGW64_VERSION_RC < 1)
// MinGW64 has a custom implementation for pow. This handles certain
// special cases that are different.
if ((x == 0.0 || isinf(x)) && isfinite(y)) {
diff --git a/src/assembler.h b/src/assembler.h
index cebd60a..ebddf82 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -248,7 +248,7 @@
// add more as needed
// Pseudo-types
NUMBER_OF_MODES, // There are at most 15 modes with noncompact encoding.
- NONE, // never recorded 32-bit value
+ NONE32, // never recorded 32-bit value
NONE64, // never recorded 64-bit value
CODE_AGE_SEQUENCE, // Not stored in RelocInfo array, used explictly by
// code aging.
@@ -320,7 +320,7 @@
return mode == DEBUG_BREAK_SLOT;
}
static inline bool IsNone(Mode mode) {
- return mode == NONE || mode == NONE64;
+ return mode == NONE32 || mode == NONE64;
}
static inline bool IsCodeAgeSequence(Mode mode) {
return mode == CODE_AGE_SEQUENCE;
diff --git a/src/ast.cc b/src/ast.cc
index c43b913..e2acd20 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -430,7 +430,7 @@
} else if (is_monomorphic_) {
receiver_types_.Add(oracle->LoadMonomorphicReceiverType(this),
zone);
- } else if (oracle->LoadIsMegamorphicWithTypeInfo(this)) {
+ } else if (oracle->LoadIsPolymorphic(this)) {
receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
oracle->CollectKeyedReceiverTypes(PropertyFeedbackId(), &receiver_types_);
}
@@ -452,7 +452,7 @@
} else if (is_monomorphic_) {
// Record receiver type for monomorphic keyed stores.
receiver_types_.Add(oracle->StoreMonomorphicReceiverType(id), zone);
- } else if (oracle->StoreIsMegamorphicWithTypeInfo(id)) {
+ } else if (oracle->StoreIsPolymorphic(id)) {
receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
}
@@ -468,7 +468,7 @@
// Record receiver type for monomorphic keyed stores.
receiver_types_.Add(
oracle->StoreMonomorphicReceiverType(id), zone);
- } else if (oracle->StoreIsMegamorphicWithTypeInfo(id)) {
+ } else if (oracle->StoreIsPolymorphic(id)) {
receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
}
@@ -1083,8 +1083,9 @@
// optimize them.
add_flag(kDontInline);
} else if (node->function()->intrinsic_type == Runtime::INLINE &&
- (node->name()->IsEqualTo(CStrVector("_ArgumentsLength")) ||
- node->name()->IsEqualTo(CStrVector("_Arguments")))) {
+ (node->name()->IsOneByteEqualTo(
+ STATIC_ASCII_VECTOR("_ArgumentsLength")) ||
+ node->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_Arguments")))) {
// Don't inline the %_ArgumentsLength or %_Arguments because their
// implementation will not work. There is no stack frame to get them
// from.
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index bf96c8c..762c4f9 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -499,7 +499,8 @@
Builtins::kEmptyFunction));
empty_function->set_code(*code);
empty_function->shared()->set_code(*code);
- Handle<String> source = factory->NewStringFromAscii(CStrVector("() {}"));
+ Handle<String> source =
+ factory->NewStringFromOneByte(STATIC_ASCII_VECTOR("() {}"));
Handle<Script> script = factory->NewScript(source);
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
empty_function->shared()->set_script(*script);
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index d61c031..fead456 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -55,7 +55,7 @@
bool Lookup(Vector<const char> name, Handle<SharedFunctionInfo>* handle) {
for (int i = 0; i < cache_->length(); i+=2) {
SeqOneByteString* str = SeqOneByteString::cast(cache_->get(i));
- if (str->IsEqualTo(name)) {
+ if (str->IsUtf8EqualTo(name)) {
*handle = Handle<SharedFunctionInfo>(
SharedFunctionInfo::cast(cache_->get(i + 1)));
return true;
diff --git a/src/builtins.cc b/src/builtins.cc
index 3143dd9..786627d 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -337,26 +337,6 @@
}
-static void MoveElements(Heap* heap,
- AssertNoAllocation* no_gc,
- FixedArray* dst,
- int dst_index,
- FixedArray* src,
- int src_index,
- int len) {
- if (len == 0) return;
- ASSERT(dst->map() != HEAP->fixed_cow_array_map());
- memmove(dst->data_start() + dst_index,
- src->data_start() + src_index,
- len * kPointerSize);
- WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
- if (mode == UPDATE_WRITE_BARRIER) {
- heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
- }
- heap->incremental_marking()->RecordWrites(dst);
-}
-
-
static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
ASSERT(dst->map() != heap->fixed_cow_array_map());
MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
@@ -724,7 +704,7 @@
if (elms_obj->IsFixedArray()) {
FixedArray* elms = FixedArray::cast(elms_obj);
AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
+ heap->MoveElements(elms, 0, 1, len - 1);
elms->set(len - 1, heap->the_hole_value());
} else {
FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
@@ -794,7 +774,7 @@
array->set_elements(elms);
} else {
AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
+ heap->MoveElements(elms, to_add, 0, len);
}
// Add the provided values.
@@ -1060,7 +1040,7 @@
} else {
FixedArray* elms = FixedArray::cast(elms_obj);
AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
+ heap->MoveElements(elms, delta, 0, actual_start);
}
elms_obj = LeftTrimFixedArray(heap, elms_obj, delta);
@@ -1076,10 +1056,9 @@
} else {
FixedArray* elms = FixedArray::cast(elms_obj);
AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc,
- elms, actual_start + item_count,
- elms, actual_start + actual_delete_count,
- (len - actual_delete_count - actual_start));
+ heap->MoveElements(elms, actual_start + item_count,
+ actual_start + actual_delete_count,
+ (len - actual_delete_count - actual_start));
FillWithHoles(heap, elms, new_length, len);
}
}
@@ -1119,10 +1098,9 @@
elms_changed = true;
} else {
AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc,
- elms, actual_start + item_count,
- elms, actual_start + actual_delete_count,
- (len - actual_delete_count - actual_start));
+ heap->MoveElements(elms, actual_start + item_count,
+ actual_start + actual_delete_count,
+ (len - actual_delete_count - actual_start));
}
}
@@ -1536,12 +1514,12 @@
static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
- KeyedLoadIC::GenerateMiss(masm, false);
+ KeyedLoadIC::GenerateMiss(masm, MISS);
}
static void Generate_KeyedLoadIC_MissForceGeneric(MacroAssembler* masm) {
- KeyedLoadIC::GenerateMiss(masm, true);
+ KeyedLoadIC::GenerateMiss(masm, MISS_FORCE_GENERIC);
}
@@ -1638,12 +1616,12 @@
static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
- KeyedStoreIC::GenerateMiss(masm, false);
+ KeyedStoreIC::GenerateMiss(masm, MISS);
}
static void Generate_KeyedStoreIC_MissForceGeneric(MacroAssembler* masm) {
- KeyedStoreIC::GenerateMiss(masm, true);
+ KeyedStoreIC::GenerateMiss(masm, MISS_FORCE_GENERIC);
}
diff --git a/src/builtins.h b/src/builtins.h
index 1ca4053..4b50b43 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -107,7 +107,7 @@
Code::kNoExtraICState) \
V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
- V(NotifyICMiss, BUILTIN, UNINITIALIZED, \
+ V(NotifyStubFailure, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(NotifyOSR, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
@@ -388,7 +388,7 @@
static void Generate_NotifyDeoptimized(MacroAssembler* masm);
static void Generate_NotifyLazyDeoptimized(MacroAssembler* masm);
static void Generate_NotifyOSR(MacroAssembler* masm);
- static void Generate_NotifyICMiss(MacroAssembler* masm);
+ static void Generate_NotifyStubFailure(MacroAssembler* masm);
static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);
static void Generate_FunctionCall(MacroAssembler* masm);
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 527abde..a02a959 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -247,7 +247,7 @@
register_params_(NULL) { }
int register_param_count_;
Register* register_params_;
- Handle<Code> deoptimization_handler_;
+ Address deoptimization_handler_;
};
@@ -422,14 +422,17 @@
public:
// Maximum length of copied elements array.
static const int kMaximumClonedLength = 8;
-
enum Mode {
CLONE_ELEMENTS,
CLONE_DOUBLE_ELEMENTS,
COPY_ON_WRITE_ELEMENTS,
- CLONE_ANY_ELEMENTS
+ CLONE_ANY_ELEMENTS,
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO,
+ LAST_CLONE_MODE = CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO
};
+ static const int kFastCloneModeCount = LAST_CLONE_MODE + 1;
+
FastCloneShallowArrayStub(Mode mode, int length)
: mode_(mode),
length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) {
@@ -445,8 +448,8 @@
Major MajorKey() { return FastCloneShallowArray; }
int MinorKey() {
- ASSERT(mode_ == 0 || mode_ == 1 || mode_ == 2 || mode_ == 3);
- return length_ * 4 + mode_;
+ ASSERT(mode_ >= 0 && mode_ <= LAST_CLONE_MODE);
+ return length_ * kFastCloneModeCount + mode_;
}
};
diff --git a/src/codegen.cc b/src/codegen.cc
index 47eddb0..2eebef6 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -174,7 +174,7 @@
}
Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
if (FLAG_log_regexp) {
- if (name->IsEqualTo(CStrVector("regexp")))
+ if (name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("regexp")))
return true;
}
return false;
diff --git a/src/compiler.cc b/src/compiler.cc
index ceac829..c4c8f99 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -316,8 +316,8 @@
if (*FLAG_hydrogen_filter != '\0') {
Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
if ((filter[0] == '-'
- && name->IsEqualTo(filter.SubVector(1, filter.length())))
- || (filter[0] != '-' && !name->IsEqualTo(filter))) {
+ && name->IsUtf8EqualTo(filter.SubVector(1, filter.length())))
+ || (filter[0] != '-' && !name->IsUtf8EqualTo(filter))) {
info()->SetCode(code);
return SetLastStatus(BAILED_OUT);
}
diff --git a/src/conversions-inl.h b/src/conversions-inl.h
index e272fe6..1b53912 100644
--- a/src/conversions-inl.h
+++ b/src/conversions-inl.h
@@ -212,7 +212,7 @@
}
// Rounding up may cause overflow.
- if ((number & ((int64_t)1 << 53)) != 0) {
+ if ((number & (static_cast<int64_t>(1) << 53)) != 0) {
exponent++;
number >>= 1;
}
diff --git a/src/d8-readline.cc b/src/d8-readline.cc
index ed7721c..8989263 100644
--- a/src/d8-readline.cc
+++ b/src/d8-readline.cc
@@ -25,8 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
#include <cstdio> // NOLINT
+#include <string.h> // NOLINT
#include <readline/readline.h> // NOLINT
#include <readline/history.h> // NOLINT
@@ -35,7 +35,6 @@
#include "d8.h"
-
// There are incompatibilities between different versions and different
// implementations of readline. This smooths out one known incompatibility.
#if RL_READLINE_VERSION >= 0x0500
@@ -58,8 +57,10 @@
static const int kMaxHistoryEntries;
private:
+#ifndef V8_SHARED
static char** AttemptedCompletion(const char* text, int start, int end);
static char* CompletionGenerator(const char* text, int state);
+#endif // V8_SHARED
static char kWordBreakCharacters[];
};
@@ -76,7 +77,15 @@
bool ReadLineEditor::Open() {
rl_initialize();
+
+#ifdef V8_SHARED
+ // Don't do completion on shared library mode
+ // http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC24
+ rl_bind_key('\t', rl_insert);
+#else
rl_attempted_completion_function = AttemptedCompletion;
+#endif // V8_SHARED
+
rl_completer_word_break_characters = kWordBreakCharacters;
rl_bind_key('\t', rl_complete);
using_history();
@@ -122,6 +131,7 @@
}
+#ifndef V8_SHARED
char** ReadLineEditor::AttemptedCompletion(const char* text,
int start,
int end) {
@@ -155,6 +165,7 @@
return NULL;
}
}
+#endif // V8_SHARED
} // namespace v8
diff --git a/src/d8.cc b/src/d8.cc
index 8233f86..5361869 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -532,8 +532,9 @@
if (args[0]->IsObject() &&
args[0]->ToObject()->Has(Symbols::length(isolate))) {
// Construct from array.
- length = convertToUint(
- args[0]->ToObject()->Get(Symbols::length(isolate)), &try_catch);
+ Local<Value> value = args[0]->ToObject()->Get(Symbols::length(isolate));
+ if (try_catch.HasCaught()) return try_catch.ReThrow();
+ length = convertToUint(value, &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
init_from_array = true;
} else {
@@ -888,9 +889,7 @@
Handle<Value> Shell::Quit(const Arguments& args) {
int exit_code = args[0]->Int32Value();
-#ifndef V8_SHARED
OnExit();
-#endif // V8_SHARED
exit(exit_code);
return Undefined();
}
@@ -1340,9 +1339,13 @@
return strcmp(static_cast<const CounterAndKey*>(a)->key,
static_cast<const CounterAndKey*>(b)->key);
}
+#endif // V8_SHARED
void Shell::OnExit() {
+ LineEditor* line_editor = LineEditor::Get();
+ if (line_editor) line_editor->Close();
+#ifndef V8_SHARED
if (i::FLAG_dump_counters) {
int number_of_counters = 0;
for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
@@ -1377,8 +1380,9 @@
}
delete counters_file_;
delete counter_map_;
-}
#endif // V8_SHARED
+}
+
static FILE* FOpen(const char* path, const char* mode) {
@@ -1503,7 +1507,6 @@
ExecuteString(input, name, true, true);
}
printf("\n");
- console->Close();
}
@@ -1954,9 +1957,7 @@
}
V8::Dispose();
-#ifndef V8_SHARED
OnExit();
-#endif // V8_SHARED
return result;
}
diff --git a/src/d8.gyp b/src/d8.gyp
index a8361e6..cce8f2a 100644
--- a/src/d8.gyp
+++ b/src/d8.gyp
@@ -45,6 +45,10 @@
'd8.cc',
],
'conditions': [
+ [ 'console=="readline"', {
+ 'libraries': [ '-lreadline', ],
+ 'sources': [ 'd8-readline.cc' ],
+ }],
[ 'component!="shared_library"', {
'sources': [ 'd8-debug.cc', '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', ],
'conditions': [
@@ -57,10 +61,6 @@
'd8_js2c',
],
}],
- [ 'console=="readline"', {
- 'libraries': [ '-lreadline', ],
- 'sources': [ 'd8-readline.cc' ],
- }],
['(OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="netbsd" \
or OS=="openbsd" or OS=="solaris" or OS=="android")', {
'sources': [ 'd8-posix.cc', ]
diff --git a/src/d8.h b/src/d8.h
index 161c653..07699e8 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -277,11 +277,11 @@
static int RunMain(Isolate* isolate, int argc, char* argv[]);
static int Main(int argc, char* argv[]);
static void Exit(int exit_code);
+ static void OnExit();
#ifndef V8_SHARED
static Handle<Array> GetCompletions(Handle<String> text,
Handle<String> full);
- static void OnExit();
static int* LookupCounter(const char* name);
static void* CreateHistogram(const char* name,
int min,
diff --git a/src/data-flow.h b/src/data-flow.h
index 71f56e7..7eeb794 100644
--- a/src/data-flow.h
+++ b/src/data-flow.h
@@ -199,6 +199,61 @@
uint32_t* data_;
};
+class GrowableBitVector BASE_EMBEDDED {
+ public:
+ class Iterator BASE_EMBEDDED {
+ public:
+ Iterator(const GrowableBitVector* target, Zone* zone)
+ : it_(target->bits_ == NULL
+ ? new(zone) BitVector(1, zone)
+ : target->bits_) { }
+ bool Done() const { return it_.Done(); }
+ void Advance() { it_.Advance(); }
+ int Current() const { return it_.Current(); }
+ private:
+ BitVector::Iterator it_;
+ };
+
+ GrowableBitVector() : bits_(NULL) { }
+
+ bool Contains(int value) const {
+ if (!InBitsRange(value)) return false;
+ return bits_->Contains(value);
+ }
+
+ void Add(int value, Zone* zone) {
+ EnsureCapacity(value, zone);
+ bits_->Add(value);
+ }
+
+ void Union(const GrowableBitVector& other, Zone* zone) {
+ for (Iterator it(&other, zone); !it.Done(); it.Advance()) {
+ Add(it.Current(), zone);
+ }
+ }
+
+ void Clear() { if (bits_ != NULL) bits_->Clear(); }
+
+ private:
+ static const int kInitialLength = 1024;
+
+ bool InBitsRange(int value) const {
+ return bits_ != NULL && bits_->length() > value;
+ }
+
+ void EnsureCapacity(int value, Zone* zone) {
+ if (InBitsRange(value)) return;
+ int new_length = bits_ == NULL ? kInitialLength : bits_->length();
+ while (new_length <= value) new_length *= 2;
+ BitVector* new_bits = new(zone) BitVector(new_length, zone);
+ if (bits_ != NULL) new_bits->CopyFrom(*bits_);
+ bits_ = new_bits;
+ }
+
+ BitVector* bits_;
+};
+
+
} } // namespace v8::internal
diff --git a/src/execution.cc b/src/execution.cc
index e43ea65..fa41167 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -127,7 +127,7 @@
ASSERT(*has_pending_exception == Isolate::Current()->has_pending_exception());
if (*has_pending_exception) {
isolate->ReportPendingMessages();
- if (isolate->pending_exception() == Failure::OutOfMemoryException()) {
+ if (isolate->pending_exception()->IsOutOfMemory()) {
if (!isolate->ignore_out_of_memory()) {
V8::FatalProcessOutOfMemory("JS", true);
}
diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc
index a126a5a..614c243 100644
--- a/src/extensions/externalize-string-extension.cc
+++ b/src/extensions/externalize-string-extension.cc
@@ -94,10 +94,10 @@
"externalizeString() can't externalize twice."));
}
if (string->IsOneByteRepresentation() && !force_two_byte) {
- char* data = new char[string->length()];
+ uint8_t* data = new uint8_t[string->length()];
String::WriteToFlat(*string, data, 0, string->length());
SimpleAsciiStringResource* resource = new SimpleAsciiStringResource(
- data, string->length());
+ reinterpret_cast<char*>(data), string->length());
result = string->MakeExternal(resource);
if (result && !string->IsSymbol()) {
HEAP->external_string_table()->AddString(*string);
diff --git a/src/factory.cc b/src/factory.cc
index 8adae4e..25f197b 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -171,7 +171,7 @@
String);
}
-Handle<String> Factory::LookupOneByteSymbol(Vector<const char> string) {
+Handle<String> Factory::LookupOneByteSymbol(Vector<const uint8_t> string) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->LookupOneByteSymbol(string),
String);
@@ -196,8 +196,8 @@
}
-Handle<String> Factory::NewStringFromAscii(Vector<const char> string,
- PretenureFlag pretenure) {
+Handle<String> Factory::NewStringFromOneByte(Vector<const uint8_t> string,
+ PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateStringFromOneByte(string, pretenure),
diff --git a/src/factory.h b/src/factory.h
index 5493335..522639d 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -84,7 +84,7 @@
return LookupUtf8Symbol(CStrVector(str));
}
Handle<String> LookupSymbol(Handle<String> str);
- Handle<String> LookupOneByteSymbol(Vector<const char> str);
+ Handle<String> LookupOneByteSymbol(Vector<const uint8_t> str);
Handle<String> LookupOneByteSymbol(Handle<SeqOneByteString>,
int from,
int length);
@@ -113,9 +113,15 @@
// two byte.
//
// ASCII strings are pretenured when used as keys in the SourceCodeCache.
- Handle<String> NewStringFromAscii(
- Vector<const char> str,
+ Handle<String> NewStringFromOneByte(
+ Vector<const uint8_t> str,
PretenureFlag pretenure = NOT_TENURED);
+ // TODO(dcarney): remove this function.
+ inline Handle<String> NewStringFromAscii(
+ Vector<const char> str,
+ PretenureFlag pretenure = NOT_TENURED) {
+ return NewStringFromOneByte(Vector<const uint8_t>::cast(str), pretenure);
+ }
// UTF8 strings are pretenured when used for regexp literal patterns and
// flags in the parser.
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 149c65d..a7a2573 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -209,7 +209,8 @@
"perform array index dehoisting")
DEFINE_bool(dead_code_elimination, true, "use dead code elimination")
DEFINE_bool(trace_dead_code_elimination, false, "trace dead code elimination")
-
+DEFINE_bool(track_allocation_sites, true,
+ "Use allocation site info to reduce transitions")
DEFINE_bool(trace_osr, false, "trace on-stack replacement")
DEFINE_int(stress_runs, 0, "number of stress runs")
DEFINE_bool(optimize_closures, true, "optimize closures")
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index faf111f..b49337a 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -448,18 +448,8 @@
StateField::encode(state) | PcField::encode(masm_->pc_offset());
ASSERT(Smi::IsValid(pc_and_state));
BailoutEntry entry = { id, pc_and_state };
-#ifdef DEBUG
- if (FLAG_enable_slow_asserts) {
- // Assert that we don't have multiple bailout entries for the same node.
- for (int i = 0; i < bailout_entries_.length(); i++) {
- if (bailout_entries_.at(i).id == entry.id) {
- AstPrinter printer;
- PrintF("%s", printer.PrintProgram(info_->function()));
- UNREACHABLE();
- }
- }
- }
-#endif // DEBUG
+ ASSERT(!prepared_bailout_ids_.Contains(id.ToInt()));
+ prepared_bailout_ids_.Add(id.ToInt(), zone());
bailout_entries_.Add(entry, zone());
}
diff --git a/src/full-codegen.h b/src/full-codegen.h
index c25076a..c4f3fcc 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -35,6 +35,7 @@
#include "code-stubs.h"
#include "codegen.h"
#include "compiler.h"
+#include "data-flow.h"
namespace v8 {
namespace internal {
@@ -816,6 +817,7 @@
int module_index_;
const ExpressionContext* context_;
ZoneList<BailoutEntry> bailout_entries_;
+ GrowableBitVector prepared_bailout_ids_;
// TODO(svenpanne) Rename this to something like back_edges_ and rename
// related functions accordingly.
ZoneList<BailoutEntry> stack_checks_;
diff --git a/src/globals.h b/src/globals.h
index babffbf..1606996 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -253,15 +253,13 @@
// other bits set.
const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
-// ASCII/UTF-16 constants
+// Latin1/UTF-16 constants
// Code-point values in Unicode 4.0 are 21 bits wide.
// Code units in UTF-16 are 16 bits wide.
typedef uint16_t uc16;
typedef int32_t uc32;
-const int kASCIISize = kCharSize;
+const int kOneByteSize = kCharSize;
const int kUC16Size = sizeof(uc16); // NOLINT
-const uc32 kMaxAsciiCharCode = 0x7f;
-const uint32_t kMaxAsciiCharCodeU = 0x7fu;
// The expression OFFSET_OF(type, field) computes the byte-offset
diff --git a/src/handles.cc b/src/handles.cc
index 16fe0c7..ed92c41 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -423,7 +423,7 @@
Vector<const SourceChar> src,
bool with_last_line) {
const int src_len = src.length();
- StringSearch<char, SourceChar> search(isolate, CStrVector("\n"));
+ StringSearch<uint8_t, SourceChar> search(isolate, STATIC_ASCII_VECTOR("\n"));
// Find and record line ends.
int position = 0;
@@ -457,7 +457,7 @@
if (content.IsAscii()) {
CalculateLineEnds(isolate,
&line_ends,
- content.ToAsciiVector(),
+ content.ToOneByteVector(),
with_last_line);
} else {
CalculateLineEnds(isolate,
diff --git a/src/heap-inl.h b/src/heap-inl.h
index deb767e..6f4b69c 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -112,10 +112,12 @@
}
-MaybeObject* Heap::AllocateSymbol(Vector<const char> str,
- int chars,
- uint32_t hash_field) {
- if (IsOneByte(str, chars)) return AllocateAsciiSymbol(str, hash_field);
+MaybeObject* Heap::AllocateSymbolFromUtf8(Vector<const char> str,
+ int chars,
+ uint32_t hash_field) {
+ if (IsOneByte(str, chars)) {
+ return AllocateOneByteSymbol(Vector<const uint8_t>::cast(str), hash_field);
+ }
return AllocateInternalSymbol<false>(str, chars, hash_field);
}
@@ -129,10 +131,10 @@
}
-MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str,
+MaybeObject* Heap::AllocateOneByteSymbol(Vector<const uint8_t> str,
uint32_t hash_field) {
if (str.length() > SeqOneByteString::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x2);
}
// Compute map and object size.
Map* map = ascii_symbol_map();
@@ -166,7 +168,7 @@
MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str,
uint32_t hash_field) {
if (str.length() > SeqTwoByteString::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x3);
}
// Compute map and object size.
Map* map = symbol_map();
@@ -261,8 +263,9 @@
MaybeObject* Heap::NumberFromUint32(
uint32_t value, PretenureFlag pretenure) {
- if ((int32_t)value >= 0 && Smi::IsValid((int32_t)value)) {
- return Smi::FromInt((int32_t)value);
+ if (static_cast<int32_t>(value) >= 0 &&
+ Smi::IsValid(static_cast<int32_t>(value))) {
+ return Smi::FromInt(static_cast<int32_t>(value));
}
// Bypass NumberFromDouble to avoid various redundant checks.
return AllocateHeapNumber(FastUI2D(value), pretenure);
diff --git a/src/heap.cc b/src/heap.cc
index 401f4f7..013a18c 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -677,6 +677,29 @@
}
+void Heap::MoveElements(FixedArray* array,
+ int dst_index,
+ int src_index,
+ int len) {
+ if (len == 0) return;
+
+ ASSERT(array->map() != HEAP->fixed_cow_array_map());
+ Object** dst_objects = array->data_start() + dst_index;
+ memmove(dst_objects,
+ array->data_start() + src_index,
+ len * kPointerSize);
+ if (!InNewSpace(array)) {
+ for (int i = 0; i < len; i++) {
+ // TODO(hpayer): check store buffer for entries
+ if (InNewSpace(dst_objects[i])) {
+ RecordWrite(array->address(), array->OffsetOfElementAt(dst_index + i));
+ }
+ }
+ }
+ incremental_marking()->RecordWrites(array);
+}
+
+
#ifdef VERIFY_HEAP
// Helper class for verifying the symbol table.
class SymbolTableVerifier : public ObjectVisitor {
@@ -2785,7 +2808,7 @@
// hash code in place. The hash code for the hidden_symbol is zero to ensure
// that it will always be at the first entry in property descriptors.
{ MaybeObject* maybe_obj =
- AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash);
+ AllocateOneByteSymbol(OneByteVector("", 0), String::kEmptyStringHash);
if (!maybe_obj->ToObject(&obj)) return false;
}
hidden_symbol_ = String::cast(obj);
@@ -2838,9 +2861,9 @@
}
set_number_string_cache(FixedArray::cast(obj));
- // Allocate cache for single character ASCII strings.
+ // Allocate cache for single character one byte strings.
{ MaybeObject* maybe_obj =
- AllocateFixedArray(String::kMaxAsciiCharCode + 1, TENURED);
+ AllocateFixedArray(String::kMaxOneByteCharCode + 1, TENURED);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_single_character_string_cache(FixedArray::cast(obj));
@@ -3309,16 +3332,16 @@
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 (static_cast<unsigned>(c1 | c2) <= String::kMaxAsciiCharCodeU) {
+ } else if (static_cast<unsigned>(c1 | c2) <= String::kMaxOneByteCharCodeU) {
// We can do this.
- ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
+ ASSERT(IsPowerOf2(String::kMaxOneByteCharCodeU + 1)); // because of this.
Object* result;
{ MaybeObject* maybe_result = heap->AllocateRawOneByteString(2);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- char* dest = SeqOneByteString::cast(result)->GetChars();
- dest[0] = static_cast<char>(c1);
- dest[1] = static_cast<char>(c2);
+ uint8_t* dest = SeqOneByteString::cast(result)->GetChars();
+ dest[0] = static_cast<uint8_t>(c1);
+ dest[1] = static_cast<uint8_t>(c2);
return result;
} else {
Object* result;
@@ -3355,19 +3378,18 @@
return MakeOrFindTwoCharacterString(this, c1, c2);
}
- bool first_is_ascii = first->IsOneByteRepresentation();
- bool second_is_ascii = second->IsOneByteRepresentation();
- bool is_ascii = first_is_ascii && second_is_ascii;
-
+ bool first_is_one_byte = first->IsOneByteRepresentation();
+ bool second_is_one_byte = second->IsOneByteRepresentation();
+ bool is_one_byte = first_is_one_byte && second_is_one_byte;
// Make sure that an out of memory exception is thrown if the length
// of the new cons string is too large.
if (length > String::kMaxLength || length < 0) {
isolate()->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x4);
}
bool is_ascii_data_in_two_byte_string = false;
- if (!is_ascii) {
+ if (!is_one_byte) {
// At least one of the strings uses two-byte representation so we
// can't use the fast case code for short ASCII strings below, but
// we can try to save memory if all chars actually fit in ASCII.
@@ -3384,15 +3406,15 @@
STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength);
ASSERT(first->IsFlat());
ASSERT(second->IsFlat());
- if (is_ascii) {
+ if (is_one_byte) {
Object* result;
{ MaybeObject* maybe_result = AllocateRawOneByteString(length);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// Copy the characters into the new object.
- char* dest = SeqOneByteString::cast(result)->GetChars();
+ uint8_t* dest = SeqOneByteString::cast(result)->GetChars();
// Copy first part.
- const char* src;
+ const uint8_t* src;
if (first->IsExternalString()) {
src = ExternalAsciiString::cast(first)->GetChars();
} else {
@@ -3414,7 +3436,7 @@
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// Copy the characters into the new object.
- char* dest = SeqOneByteString::cast(result)->GetChars();
+ uint8_t* dest = SeqOneByteString::cast(result)->GetChars();
String::WriteToFlat(first, dest, 0, first_length);
String::WriteToFlat(second, dest + first_length, 0, second_length);
isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
@@ -3433,7 +3455,7 @@
}
}
- Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
+ Map* map = (is_one_byte || is_ascii_data_in_two_byte_string) ?
cons_ascii_string_map() : cons_string_map();
Object* result;
@@ -3481,17 +3503,17 @@
// WriteToFlat takes care of the case when an indirect string has a
// different encoding from its underlying string. These encodings may
// differ because of externalization.
- bool is_ascii = buffer->IsOneByteRepresentation();
- { MaybeObject* maybe_result = is_ascii
+ bool is_one_byte = buffer->IsOneByteRepresentation();
+ { MaybeObject* maybe_result = is_one_byte
? AllocateRawOneByteString(length, pretenure)
: AllocateRawTwoByteString(length, pretenure);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
String* string_result = String::cast(result);
// Copy the characters into the new object.
- if (is_ascii) {
+ if (is_one_byte) {
ASSERT(string_result->IsOneByteRepresentation());
- char* dest = SeqOneByteString::cast(string_result)->GetChars();
+ uint8_t* dest = SeqOneByteString::cast(string_result)->GetChars();
String::WriteToFlat(buffer, dest, start, end);
} else {
ASSERT(string_result->IsTwoByteRepresentation());
@@ -3551,7 +3573,7 @@
size_t length = resource->length();
if (length > static_cast<size_t>(String::kMaxLength)) {
isolate()->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x5);
}
ASSERT(String::IsAscii(resource->data(), static_cast<int>(length)));
@@ -3576,15 +3598,15 @@
size_t length = resource->length();
if (length > static_cast<size_t>(String::kMaxLength)) {
isolate()->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x6);
}
// For small strings we check whether the resource contains only
- // ASCII characters. If yes, we use a different string map.
+ // one byte characters. If yes, we use a different string map.
static const size_t kAsciiCheckLengthLimit = 32;
- bool is_ascii = length <= kAsciiCheckLengthLimit &&
- String::IsAscii(resource->data(), static_cast<int>(length));
- Map* map = is_ascii ?
+ bool is_one_byte = length <= kAsciiCheckLengthLimit &&
+ String::IsOneByte(resource->data(), static_cast<int>(length));
+ Map* map = is_one_byte ?
external_string_with_ascii_data_map() : external_string_map();
Object* result;
{ MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
@@ -3601,15 +3623,15 @@
MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
- if (code <= String::kMaxAsciiCharCode) {
+ if (code <= String::kMaxOneByteCharCode) {
Object* value = single_character_string_cache()->get(code);
if (value != undefined_value()) return value;
- char buffer[1];
- buffer[0] = static_cast<char>(code);
+ uint8_t buffer[1];
+ buffer[0] = static_cast<uint8_t>(code);
Object* result;
MaybeObject* maybe_result =
- LookupOneByteSymbol(Vector<const char>(buffer, 1));
+ LookupOneByteSymbol(Vector<const uint8_t>(buffer, 1));
if (!maybe_result->ToObject(&result)) return maybe_result;
single_character_string_cache()->set(code, result);
@@ -3628,7 +3650,7 @@
MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
if (length < 0 || length > ByteArray::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x7);
}
if (pretenure == NOT_TENURED) {
return AllocateByteArray(length);
@@ -3650,7 +3672,7 @@
MaybeObject* Heap::AllocateByteArray(int length) {
if (length < 0 || length > ByteArray::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x8);
}
int size = ByteArray::SizeFor(length);
AllocationSpace space =
@@ -4520,7 +4542,7 @@
}
-MaybeObject* Heap::AllocateStringFromOneByte(Vector<const char> string,
+MaybeObject* Heap::AllocateStringFromOneByte(Vector<const uint8_t> string,
PretenureFlag pretenure) {
int length = string.length();
if (length == 1) {
@@ -4533,7 +4555,9 @@
}
// Copy the characters into the new object.
- CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(), length);
+ CopyChars(SeqOneByteString::cast(result)->GetChars(),
+ string.start(),
+ length);
return result;
}
@@ -4579,11 +4603,11 @@
int length = string.length();
const uc16* start = string.start();
- if (String::IsAscii(start, length)) {
+ if (String::IsOneByte(start, length)) {
MaybeObject* maybe_result = AllocateRawOneByteString(length, pretenure);
if (!maybe_result->ToObject(&result)) return maybe_result;
CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length);
- } else { // It's not an ASCII string.
+ } else { // It's not a one byte string.
MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
if (!maybe_result->ToObject(&result)) return maybe_result;
CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
@@ -4630,7 +4654,7 @@
class AllocateInternalSymbolHelper< Vector<const char> > {
public:
static inline void WriteOneByteData(Vector<const char> vector,
- char* chars,
+ uint8_t* chars,
int len) {
// Only works for ascii.
ASSERT(vector.length() == len);
@@ -4672,7 +4696,7 @@
template<>
class AllocateInternalSymbolHelper<String*> {
public:
- static inline void WriteOneByteData(String* s, char* chars, int len) {
+ static inline void WriteOneByteData(String* s, uint8_t* chars, int len) {
ASSERT(s->length() == len);
String::WriteToFlat(s, chars, 0, len);
}
@@ -4699,13 +4723,13 @@
if (is_one_byte) {
if (chars > SeqOneByteString::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x9);
}
map = ascii_symbol_map();
size = SeqOneByteString::SizeFor(chars);
} else {
if (chars > SeqTwoByteString::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0xa);
}
map = symbol_map();
size = SeqTwoByteString::SizeFor(chars);
@@ -4750,7 +4774,7 @@
MaybeObject* Heap::AllocateRawOneByteString(int length,
PretenureFlag pretenure) {
if (length < 0 || length > SeqOneByteString::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0xb);
}
int size = SeqOneByteString::SizeFor(length);
@@ -4782,14 +4806,16 @@
String::cast(result)->set_hash_field(String::kEmptyHashField);
ASSERT_EQ(size, HeapObject::cast(result)->Size());
+#ifndef ENABLE_LATIN_1
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
// Initialize string's content to ensure ASCII-ness (character range 0-127)
// as required when verifying the heap.
- char* dest = SeqOneByteString::cast(result)->GetChars();
+ uint8_t* dest = SeqOneByteString::cast(result)->GetChars();
memset(dest, 0x0F, length * kCharSize);
}
#endif
+#endif
return result;
}
@@ -4798,7 +4824,7 @@
MaybeObject* Heap::AllocateRawTwoByteString(int length,
PretenureFlag pretenure) {
if (length < 0 || length > SeqTwoByteString::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0xc);
}
int size = SeqTwoByteString::SizeFor(length);
ASSERT(size <= SeqTwoByteString::kMaxSize);
@@ -4867,7 +4893,7 @@
MaybeObject* Heap::AllocateRawFixedArray(int length) {
if (length < 0 || length > FixedArray::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0xd);
}
ASSERT(length > 0);
// Use the general function if we're forced to always allocate.
@@ -4943,7 +4969,7 @@
MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
if (length < 0 || length > FixedArray::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0xe);
}
AllocationSpace space =
@@ -5076,7 +5102,7 @@
MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
PretenureFlag pretenure) {
if (length < 0 || length > FixedDoubleArray::kMaxLength) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0xf);
}
AllocationSpace space =
@@ -5628,7 +5654,7 @@
}
-MaybeObject* Heap::LookupOneByteSymbol(Vector<const char> string) {
+MaybeObject* Heap::LookupOneByteSymbol(Vector<const uint8_t> string) {
Object* symbol = NULL;
Object* new_table;
{ MaybeObject* maybe_new_table =
diff --git a/src/heap.h b/src/heap.h
index 9281fa9..a2564a5 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -699,8 +699,15 @@
// failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateStringFromOneByte(
- Vector<const char> str,
+ Vector<const uint8_t> str,
PretenureFlag pretenure = NOT_TENURED);
+ // TODO(dcarney): remove this function.
+ MUST_USE_RESULT inline MaybeObject* AllocateStringFromOneByte(
+ Vector<const char> str,
+ PretenureFlag pretenure = NOT_TENURED) {
+ return AllocateStringFromOneByte(Vector<const uint8_t>::cast(str),
+ pretenure);
+ }
MUST_USE_RESULT inline MaybeObject* AllocateStringFromUtf8(
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
@@ -716,12 +723,13 @@
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT inline MaybeObject* AllocateSymbol(Vector<const char> str,
- int chars,
- uint32_t hash_field);
+ MUST_USE_RESULT inline MaybeObject* AllocateSymbolFromUtf8(
+ Vector<const char> str,
+ int chars,
+ uint32_t hash_field);
- MUST_USE_RESULT inline MaybeObject* AllocateAsciiSymbol(
- Vector<const char> str,
+ MUST_USE_RESULT inline MaybeObject* AllocateOneByteSymbol(
+ Vector<const uint8_t> str,
uint32_t hash_field);
MUST_USE_RESULT inline MaybeObject* AllocateTwoByteSymbol(
@@ -805,6 +813,10 @@
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateUninitializedFixedArray(int length);
+ // Move len elements within a given array from src_index index to dst_index
+ // index.
+ void MoveElements(FixedArray* array, int dst_index, int src_index, int len);
+
// Make a copy of src and return it. Returns
// Failure::RetryAfterGC(requested_bytes, space) if the allocation failed.
MUST_USE_RESULT inline MaybeObject* CopyFixedArray(FixedArray* src);
@@ -1038,7 +1050,7 @@
MUST_USE_RESULT MaybeObject* LookupUtf8Symbol(const char* str) {
return LookupUtf8Symbol(CStrVector(str));
}
- MUST_USE_RESULT MaybeObject* LookupOneByteSymbol(Vector<const char> str);
+ MUST_USE_RESULT MaybeObject* LookupOneByteSymbol(Vector<const uint8_t> str);
MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol(Vector<const uc16> str);
MUST_USE_RESULT MaybeObject* LookupSymbol(String* str);
MUST_USE_RESULT MaybeObject* LookupOneByteSymbol(
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 55beb3a..c39f8a4 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -152,8 +152,11 @@
for (int i = 0; i < push_count; ++i) {
instr->AddPushedValue(environment->ExpressionStackAt(i));
}
- for (int i = 0; i < environment->assigned_variables()->length(); ++i) {
- int index = environment->assigned_variables()->at(i);
+ for (GrowableBitVector::Iterator it(environment->assigned_variables(),
+ zone());
+ !it.Done();
+ it.Advance()) {
+ int index = it.Current();
instr->AddAssignedValue(index, environment->Lookup(index));
}
environment->ClearHistory();
@@ -5399,6 +5402,10 @@
Handle<String> name,
LookupResult* lookup,
bool is_store) {
+ if (type->has_named_interceptor()) {
+ lookup->InterceptorResult(NULL);
+ return false;
+ }
// If we directly find a field, the access can be inlined.
type->LookupDescriptor(NULL, *name, lookup);
if (lookup->IsField()) return true;
@@ -6599,7 +6606,7 @@
HInstruction* result = NULL;
if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
- if (!name->IsEqualTo(CStrVector("length"))) return false;
+ if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("length"))) return false;
if (function_state()->outer() == NULL) {
HInstruction* elements = AddInstruction(
@@ -8495,7 +8502,9 @@
Literal* literal = expr->right()->AsLiteral();
if (literal == NULL) return false;
if (!literal->handle()->IsString()) return false;
- if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false;
+ if (!call->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_ClassOf"))) {
+ return false;
+ }
ASSERT(call->arguments()->length() == 1);
return true;
}
@@ -9566,7 +9575,6 @@
Zone* zone)
: closure_(closure),
values_(0, zone),
- assigned_variables_(4, zone),
frame_type_(JS_FUNCTION),
parameter_count_(0),
specials_count_(1),
@@ -9583,7 +9591,6 @@
HEnvironment::HEnvironment(Zone* zone)
: values_(0, zone),
- assigned_variables_(0, zone),
frame_type_(STUB),
parameter_count_(0),
specials_count_(0),
@@ -9600,7 +9607,6 @@
HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
: values_(0, zone),
- assigned_variables_(0, zone),
frame_type_(JS_FUNCTION),
parameter_count_(0),
specials_count_(1),
@@ -9622,7 +9628,6 @@
Zone* zone)
: closure_(closure),
values_(arguments, zone),
- assigned_variables_(0, zone),
frame_type_(frame_type),
parameter_count_(arguments),
local_count_(0),
@@ -9651,7 +9656,7 @@
void HEnvironment::Initialize(const HEnvironment* other) {
closure_ = other->closure();
values_.AddAll(other->values_, zone());
- assigned_variables_.AddAll(other->assigned_variables_, zone());
+ assigned_variables_.Union(other->assigned_variables_, zone());
frame_type_ = other->frame_type_;
parameter_count_ = other->parameter_count_;
local_count_ = other->local_count_;
@@ -9695,9 +9700,7 @@
void HEnvironment::Bind(int index, HValue* value) {
ASSERT(value != NULL);
- if (!assigned_variables_.Contains(index)) {
- assigned_variables_.Add(index, zone());
- }
+ assigned_variables_.Add(index, zone());
values_[index] = value;
}
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 0837bf9..eb5ec52 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -450,7 +450,7 @@
// Simple accessors.
Handle<JSFunction> closure() const { return closure_; }
const ZoneList<HValue*>* values() const { return &values_; }
- const ZoneList<int>* assigned_variables() const {
+ const GrowableBitVector* assigned_variables() const {
return &assigned_variables_;
}
FrameType frame_type() const { return frame_type_; }
@@ -557,7 +557,7 @@
void ClearHistory() {
pop_count_ = 0;
push_count_ = 0;
- assigned_variables_.Rewind(0);
+ assigned_variables_.Clear();
}
void SetValueAt(int index, HValue* value) {
@@ -606,7 +606,7 @@
Handle<JSFunction> closure_;
// Value array [parameters] [specials] [locals] [temporaries].
ZoneList<HValue*> values_;
- ZoneList<int> assigned_variables_;
+ GrowableBitVector assigned_variables_;
FrameType frame_type_;
int parameter_count_;
int specials_count_;
diff --git a/src/ia32/assembler-ia32-inl.h b/src/ia32/assembler-ia32-inl.h
index f838592..56d88b0 100644
--- a/src/ia32/assembler-ia32-inl.h
+++ b/src/ia32/assembler-ia32-inl.h
@@ -300,7 +300,7 @@
Immediate::Immediate(int x) {
x_ = x;
- rmode_ = RelocInfo::NONE;
+ rmode_ = RelocInfo::NONE32;
}
@@ -326,20 +326,20 @@
} else {
// no relocation needed
x_ = reinterpret_cast<intptr_t>(obj);
- rmode_ = RelocInfo::NONE;
+ rmode_ = RelocInfo::NONE32;
}
}
Immediate::Immediate(Smi* value) {
x_ = reinterpret_cast<intptr_t>(value);
- rmode_ = RelocInfo::NONE;
+ rmode_ = RelocInfo::NONE32;
}
Immediate::Immediate(Address addr) {
x_ = reinterpret_cast<int32_t>(addr);
- rmode_ = RelocInfo::NONE;
+ rmode_ = RelocInfo::NONE32;
}
@@ -396,7 +396,7 @@
void Assembler::emit_w(const Immediate& x) {
- ASSERT(x.rmode_ == RelocInfo::NONE);
+ ASSERT(RelocInfo::IsNone(x.rmode_));
uint16_t value = static_cast<uint16_t>(x.x_);
reinterpret_cast<uint16_t*>(pc_)[0] = value;
pc_ += sizeof(uint16_t);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index 750746c..fd53bbf 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -236,7 +236,7 @@
#endif
// Patch the code.
- patcher.masm()->call(target, RelocInfo::NONE);
+ patcher.masm()->call(target, RelocInfo::NONE32);
// Check that the size of the code generated is as expected.
ASSERT_EQ(kCallCodeSize,
@@ -255,11 +255,11 @@
Operand::Operand(Register base, int32_t disp, RelocInfo::Mode rmode) {
// [base + disp/r]
- if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) {
+ if (disp == 0 && RelocInfo::IsNone(rmode) && !base.is(ebp)) {
// [base]
set_modrm(0, base);
if (base.is(esp)) set_sib(times_1, esp, base);
- } else if (is_int8(disp) && rmode == RelocInfo::NONE) {
+ } else if (is_int8(disp) && RelocInfo::IsNone(rmode)) {
// [base + disp8]
set_modrm(1, base);
if (base.is(esp)) set_sib(times_1, esp, base);
@@ -280,11 +280,11 @@
RelocInfo::Mode rmode) {
ASSERT(!index.is(esp)); // illegal addressing mode
// [base + index*scale + disp/r]
- if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) {
+ if (disp == 0 && RelocInfo::IsNone(rmode) && !base.is(ebp)) {
// [base + index*scale]
set_modrm(0, esp);
set_sib(scale, index, base);
- } else if (is_int8(disp) && rmode == RelocInfo::NONE) {
+ } else if (is_int8(disp) && RelocInfo::IsNone(rmode)) {
// [base + index*scale + disp8]
set_modrm(1, esp);
set_sib(scale, index, base);
@@ -1180,7 +1180,7 @@
EnsureSpace ensure_space(this);
// Only use test against byte for registers that have a byte
// variant: eax, ebx, ecx, and edx.
- if (imm.rmode_ == RelocInfo::NONE &&
+ if (RelocInfo::IsNone(imm.rmode_) &&
is_uint8(imm.x_) &&
reg.is_byte_register()) {
uint8_t imm8 = imm.x_;
@@ -2614,7 +2614,7 @@
pc_ += length;
// Emit relocation information if necessary.
- if (length >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) {
+ if (length >= sizeof(int32_t) && !RelocInfo::IsNone(adr.rmode_)) {
pc_ -= sizeof(int32_t); // pc_ must be *at* disp32
RecordRelocInfo(adr.rmode_);
pc_ += sizeof(int32_t);
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 28e8339..ca785e9 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -337,12 +337,12 @@
return Immediate(label);
}
- bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; }
+ bool is_zero() const { return x_ == 0 && RelocInfo::IsNone(rmode_); }
bool is_int8() const {
- return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
+ return -128 <= x_ && x_ < 128 && RelocInfo::IsNone(rmode_);
}
bool is_int16() const {
- return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE;
+ return -32768 <= x_ && x_ < 32768 && RelocInfo::IsNone(rmode_);
}
private:
@@ -382,20 +382,20 @@
// [base + disp/r]
explicit Operand(Register base, int32_t disp,
- RelocInfo::Mode rmode = RelocInfo::NONE);
+ RelocInfo::Mode rmode = RelocInfo::NONE32);
// [base + index*scale + disp/r]
explicit Operand(Register base,
Register index,
ScaleFactor scale,
int32_t disp,
- RelocInfo::Mode rmode = RelocInfo::NONE);
+ RelocInfo::Mode rmode = RelocInfo::NONE32);
// [index*scale + disp/r]
explicit Operand(Register index,
ScaleFactor scale,
int32_t disp,
- RelocInfo::Mode rmode = RelocInfo::NONE);
+ RelocInfo::Mode rmode = RelocInfo::NONE32);
static Operand StaticVariable(const ExternalReference& ext) {
return Operand(reinterpret_cast<int32_t>(ext.address()),
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index da9f13e..c689afb 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -575,7 +575,7 @@
#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
-void Builtins::Generate_NotifyICMiss(MacroAssembler* masm) {
+void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
@@ -584,7 +584,7 @@
// stubs that tail call the runtime on deopts passing their parameters in
// registers.
__ pushad();
- __ CallRuntime(Runtime::kNotifyICMiss, 0);
+ __ CallRuntime(Runtime::kNotifyStubFailure, 0);
__ popad();
// Tear down internal frame.
}
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 92f55b8..28663ab 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -48,7 +48,7 @@
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
- isolate->builtins()->KeyedLoadIC_Miss();
+ FUNCTION_ADDR(KeyedLoadIC_Miss);
}
@@ -323,6 +323,7 @@
MacroAssembler* masm,
int length,
FastCloneShallowArrayStub::Mode mode,
+ AllocationSiteInfoMode allocation_site_info_mode,
Label* fail) {
// Registers on entry:
//
@@ -336,7 +337,12 @@
? FixedDoubleArray::SizeFor(length)
: FixedArray::SizeFor(length);
}
- int size = JSArray::kSize + elements_size;
+ int size = JSArray::kSize;
+ int allocation_info_start = size;
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ size += AllocationSiteInfo::kSize;
+ }
+ size += elements_size;
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
@@ -346,6 +352,13 @@
}
__ AllocateInNewSpace(size, eax, ebx, edx, fail, flags);
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ mov(FieldOperand(eax, allocation_info_start),
+ Immediate(Handle<Map>(masm->isolate()->heap()->
+ allocation_site_info_map())));
+ __ mov(FieldOperand(eax, allocation_info_start + kPointerSize), ecx);
+ }
+
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length == 0)) {
@@ -358,7 +371,11 @@
// Get hold of the elements array of the boilerplate and setup the
// elements pointer in the resulting object.
__ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
- __ lea(edx, Operand(eax, JSArray::kSize));
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ lea(edx, Operand(eax, JSArray::kSize + AllocationSiteInfo::kSize));
+ } else {
+ __ lea(edx, Operand(eax, JSArray::kSize));
+ }
__ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
// Copy the elements array.
@@ -408,20 +425,31 @@
FastCloneShallowArrayStub::Mode mode = mode_;
// ecx is boilerplate object.
+ AllocationSiteInfoMode allocation_site_info_mode =
+ DONT_TRACK_ALLOCATION_SITE_INFO;
+ if (mode == CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO) {
+ mode = CLONE_ANY_ELEMENTS;
+ allocation_site_info_mode = TRACK_ALLOCATION_SITE_INFO;
+ }
+
if (mode == CLONE_ANY_ELEMENTS) {
Label double_elements, check_fast_elements;
__ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset));
__ CheckMap(ebx, factory->fixed_cow_array_map(),
&check_fast_elements, DONT_DO_SMI_CHECK);
GenerateFastCloneShallowArrayCommon(masm, 0,
- COPY_ON_WRITE_ELEMENTS, &slow_case);
+ COPY_ON_WRITE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
__ ret(3 * kPointerSize);
__ bind(&check_fast_elements);
__ CheckMap(ebx, factory->fixed_array_map(),
&double_elements, DONT_DO_SMI_CHECK);
GenerateFastCloneShallowArrayCommon(masm, length_,
- CLONE_ELEMENTS, &slow_case);
+ CLONE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
__ ret(3 * kPointerSize);
__ bind(&double_elements);
@@ -450,7 +478,8 @@
__ pop(ecx);
}
- GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
+ GenerateFastCloneShallowArrayCommon(masm, length_, mode,
+ allocation_site_info_mode, &slow_case);
// Return and remove the on-stack parameters.
__ ret(3 * kPointerSize);
@@ -4849,6 +4878,19 @@
}
+static void JumpIfOOM(MacroAssembler* masm,
+ Register value,
+ Register scratch,
+ Label* oom_label) {
+ __ mov(scratch, value);
+ STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
+ STATIC_ASSERT(kFailureTag == 3);
+ __ and_(scratch, 0xf);
+ __ cmp(scratch, 0xf);
+ __ j(equal, oom_label);
+}
+
+
void CEntryStub::GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
Label* throw_termination_exception,
@@ -4946,8 +4988,7 @@
__ j(zero, &retry, Label::kNear);
// Special handling of out of memory exceptions.
- __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
- __ j(equal, throw_out_of_memory_exception);
+ JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
__ mov(eax, Operand::StaticVariable(pending_exception_address));
@@ -5029,7 +5070,10 @@
// Set pending exception and eax to out of memory exception.
ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
isolate);
- __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
+ Label already_have_failure;
+ JumpIfOOM(masm, eax, ecx, &already_have_failure);
+ __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException(0x1)));
+ __ bind(&already_have_failure);
__ mov(Operand::StaticVariable(pending_exception), eax);
// Fall through to the next label.
@@ -5472,10 +5516,10 @@
// Fast case of Heap::LookupSingleCharacterStringFromCode.
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiShiftSize == 0);
- ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
+ ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
__ test(code_,
Immediate(kSmiTagMask |
- ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
+ ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
__ j(not_zero, &slow_case_);
Factory* factory = masm->isolate()->factory();
@@ -6434,7 +6478,12 @@
// Compare lengths - strings up to min-length are equal.
__ bind(&compare_lengths);
__ test(length_delta, length_delta);
+#ifndef ENABLE_LATIN_1
__ j(not_zero, &result_not_equal, Label::kNear);
+#else
+ Label length_not_equal;
+ __ j(not_zero, &length_not_equal, Label::kNear);
+#endif
// Result is EQUAL.
STATIC_ASSERT(EQUAL == 0);
@@ -6443,8 +6492,19 @@
__ ret(0);
Label result_greater;
- __ bind(&result_not_equal);
+#ifdef ENABLE_LATIN_1
+ Label result_less;
+ __ bind(&length_not_equal);
__ j(greater, &result_greater, Label::kNear);
+ __ jmp(&result_less, Label::kNear);
+#endif
+ __ bind(&result_not_equal);
+#ifndef ENABLE_LATIN_1
+ __ j(greater, &result_greater, Label::kNear);
+#else
+ __ j(above, &result_greater, Label::kNear);
+ __ bind(&result_less);
+#endif
// Result is LESS.
__ Set(eax, Immediate(Smi::FromInt(LESS)));
@@ -7470,7 +7530,7 @@
// Call the entry hook.
int32_t hook_location = reinterpret_cast<int32_t>(&entry_hook_);
- __ call(Operand(hook_location, RelocInfo::NONE));
+ __ call(Operand(hook_location, RelocInfo::NONE32));
__ add(esp, Immediate(2 * kPointerSize));
// Restore ecx.
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 45a968d..cb2fa26 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -388,6 +388,7 @@
#define __ ACCESS_MASM(masm)
+
void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
MacroAssembler* masm) {
// ----------- S t a t e -------------
@@ -420,6 +421,10 @@
// -----------------------------------
Label loop, entry, convert_hole, gc_required, only_change_map;
+ if (FLAG_track_allocation_sites) {
+ masm->TestJSArrayForAllocationSiteInfo(edx, edi, fail);
+ }
+
// Check for empty arrays, which only require a map transition and no changes
// to the backing store.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
@@ -938,7 +943,7 @@
} else {
Code* stub = GetCodeAgeStub(age, parity);
CodePatcher patcher(sequence, young_length);
- patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE);
+ patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32);
}
}
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index 3233c27..72a8592 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -158,7 +158,7 @@
Address call_address = code_start_address + deopt_data->Pc(i)->value();
CodePatcher patcher(call_address, patch_size());
Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
- patcher.masm()->call(deopt_entry, RelocInfo::NONE);
+ patcher.masm()->call(deopt_entry, RelocInfo::NONE32);
// We use RUNTIME_ENTRY for deoptimization bailouts.
RelocInfo rinfo(call_address + 1, // 1 after the call opcode.
RelocInfo::RUNTIME_ENTRY,
@@ -565,35 +565,41 @@
// FROM TO <-ebp
// | .... | | .... |
// +-------------------------+ +-------------------------+
- // | JSFunction continuation | | JSFunction continuation |
+ // | JSFunction continuation | | parameter 1 |
+ // +-------------------------+ +-------------------------+
+ // | | saved frame (ebp) | | .... |
+ // | +=========================+<-ebp +-------------------------+
+ // | | JSFunction context | | parameter n |
+ // v +-------------------------+ +-------------------------|
+ // | COMPILED_STUB marker | | JSFunction continuation |
// +-------------------------+ +-------------------------+<-esp
- // | | saved frame (ebp) |
- // | +=========================+<-ebp
- // | | JSFunction context |
- // v +-------------------------+
- // | COMPILED_STUB marker | ebp = saved frame
- // +-------------------------+ esi = JSFunction context
- // | |
- // | ... |
- // | |
- // +-------------------------+<-esp
+ // | | eax = number of parameters
+ // | ... | ebx = failure handler address
+ // | | ebp = saved frame
+ // +-------------------------+<-esp esi = JSFunction context
//
//
- int output_frame_size = 1 * kPointerSize;
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, 0);
- Code* notify_miss =
- isolate_->builtins()->builtin(Builtins::kNotifyICMiss);
- output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
- output_frame->SetContinuation(
- reinterpret_cast<uint32_t>(notify_miss->entry()));
ASSERT(compiled_code_->kind() == Code::COMPILED_STUB);
int major_key = compiled_code_->major_key();
CodeStubInterfaceDescriptor* descriptor =
isolate_->code_stub_interface_descriptor(major_key);
- Handle<Code> miss_ic(descriptor->deoptimization_handler_);
- output_frame->SetPc(reinterpret_cast<intptr_t>(miss_ic->instruction_start()));
+
+ int output_frame_size =
+ (1 + descriptor->register_param_count_) * kPointerSize;
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, 0);
+ Code* notify_failure =
+ isolate_->builtins()->builtin(Builtins::kNotifyStubFailure);
+ output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
+ output_frame->SetContinuation(
+ reinterpret_cast<uint32_t>(notify_failure->entry()));
+
+ Code* code;
+ SaveFPRegsMode mode =
+ CpuFeatures::IsSupported(SSE2) ? kSaveFPRegs : kDontSaveFPRegs;
+ CEntryStub(1, mode).FindCodeInCache(&code, isolate_);
+ output_frame->SetPc(reinterpret_cast<intptr_t>(code->instruction_start()));
unsigned input_frame_size = input_->GetFrameSize();
intptr_t value = input_->GetFrameSlot(input_frame_size - kPointerSize);
output_frame->SetFrameSlot(0, value);
@@ -603,20 +609,22 @@
value = input_->GetFrameSlot(input_frame_size - 3 * kPointerSize);
output_frame->SetRegister(esi.code(), value);
- Translation::Opcode opcode =
- static_cast<Translation::Opcode>(iterator->Next());
- ASSERT(opcode == Translation::REGISTER);
- USE(opcode);
- int input_reg = iterator->Next();
- intptr_t input_value = input_->GetRegister(input_reg);
- output_frame->SetRegister(edx.code(), input_value);
+ int parameter_offset = kPointerSize * descriptor->register_param_count_;
+ for (int i = 0; i < descriptor->register_param_count_; ++i) {
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ ASSERT(opcode == Translation::REGISTER);
+ USE(opcode);
+ int input_reg = iterator->Next();
+ intptr_t reg_value = input_->GetRegister(input_reg);
+ output_frame->SetFrameSlot(parameter_offset, reg_value);
+ parameter_offset -= kPointerSize;
+ }
- int32_t next = iterator->Next();
- opcode = static_cast<Translation::Opcode>(next);
- ASSERT(opcode == Translation::REGISTER);
- input_reg = iterator->Next();
- input_value = input_->GetRegister(input_reg);
- output_frame->SetRegister(ecx.code(), input_value);
+ intptr_t handler =
+ reinterpret_cast<intptr_t>(descriptor->deoptimization_handler_);
+ output_frame->SetRegister(eax.code(), descriptor->register_param_count_);
+ output_frame->SetRegister(ebx.code(), handler);
ASSERT(frame_index == 0);
output_[frame_index] = output_frame;
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 95e95d4..7cb6558 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -127,7 +127,7 @@
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
- info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+ info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
__ int3();
}
#endif
@@ -1678,6 +1678,15 @@
FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
: FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
+
+ // Tracking allocation info allows us to pre-transition later if it makes
+ // sense.
+ if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS &&
+ FLAG_track_allocation_sites) {
+ mode = FastCloneShallowArrayStub::
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO;
+ }
+
FastCloneShallowArrayStub stub(mode, length);
__ CallStub(&stub);
}
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index ac5af2b..eb69658 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -647,7 +647,7 @@
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -689,7 +689,7 @@
__ TailCallExternalReference(ref, 2, 1);
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -714,7 +714,7 @@
__ mov(eax, unmapped_location);
__ Ret();
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -743,7 +743,7 @@
__ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
__ Ret();
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -1385,7 +1385,7 @@
}
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
// ----------- S t a t e -------------
// -- ecx : key
// -- edx : receiver
@@ -1400,7 +1400,7 @@
__ push(ebx); // return address
// Perform tail call to the entry.
- ExternalReference ref = force_generic
+ ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
@@ -1598,7 +1598,7 @@
}
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@@ -1613,7 +1613,7 @@
__ push(ebx);
// Do tail-call to runtime routine.
- ExternalReference ref = force_generic
+ ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 761f516..e9d7509 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -135,7 +135,7 @@
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
- info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+ info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
__ int3();
}
#endif
@@ -2411,7 +2411,7 @@
ASSERT(!temp.is(temp2));
__ JumpIfSmi(input, is_false);
- if (class_name->IsEqualTo(CStrVector("Function"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
// Assuming the following assertions, we can use the same compares to test
// for both being a function type and being in the object type range.
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
@@ -2441,7 +2441,7 @@
__ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
// Objects with a non-function constructor have class 'Object'.
__ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
- if (class_name->IsEqualTo(CStrVector("Object"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
__ j(not_equal, is_true);
} else {
__ j(not_equal, is_false);
@@ -4432,7 +4432,7 @@
Register result = ToRegister(instr->result());
ASSERT(!char_code.is(result));
- __ cmp(char_code, String::kMaxAsciiCharCode);
+ __ cmp(char_code, String::kMaxOneByteCharCode);
__ j(above, deferred->entry());
__ Set(result, Immediate(factory()->single_character_string_cache()));
__ mov(result, FieldOperand(result,
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index e5b580b..d5013d7 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -170,7 +170,7 @@
Label done;
cmp(src, Immediate(0));
movdbl(scratch,
- Operand(reinterpret_cast<int32_t>(&kUint32Bias), RelocInfo::NONE));
+ Operand(reinterpret_cast<int32_t>(&kUint32Bias), RelocInfo::NONE32));
cvtsi2sd(dst, src);
j(not_sign, &done, Label::kNear);
addsd(dst, scratch);
@@ -3051,6 +3051,30 @@
j(not_equal, &next);
}
+
+void MacroAssembler::TestJSArrayForAllocationSiteInfo(
+ Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present) {
+ Label no_info_available;
+ ExternalReference new_space_start =
+ ExternalReference::new_space_start(isolate());
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+
+ lea(scratch_reg, Operand(receiver_reg,
+ JSArray::kSize + AllocationSiteInfo::kSize));
+ cmp(scratch_reg, Immediate(new_space_start));
+ j(less, &no_info_available);
+ cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
+ j(greater_equal, &no_info_available);
+ cmp(MemOperand(scratch_reg, 0),
+ Immediate(Handle<Map>(isolate()->heap()->allocation_site_info_map())));
+ j(equal, allocation_info_present);
+ bind(&no_info_available);
+}
+
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index cc7ef29..ac1a100 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -859,6 +859,16 @@
// in eax. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Label* call_runtime);
+ // AllocationSiteInfo support. Arrays may have an associated
+ // AllocationSiteInfo object that can be checked for in order to pretransition
+ // to another type.
+ // On entry, receiver_reg should point to the array object.
+ // scratch_reg gets clobbered.
+ // If allocation info is present, jump to allocation_info_present
+ void TestJSArrayForAllocationSiteInfo(Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present);
+
private:
bool generating_stub_;
bool allow_stub_calls_;
diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
index af6a9e4..49c75e1 100644
--- a/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -217,7 +217,7 @@
// If input is ASCII, don't even bother calling here if the string to
// match contains a non-ASCII character.
if (mode_ == ASCII) {
- ASSERT(String::IsAscii(str.start(), str.length()));
+ ASSERT(String::IsOneByte(str.start(), str.length()));
}
#endif
int byte_length = str.length() * char_size();
@@ -344,7 +344,19 @@
__ or_(eax, 0x20); // Convert match character to lower-case.
__ lea(ecx, Operand(eax, -'a'));
__ cmp(ecx, static_cast<int32_t>('z' - 'a')); // Is eax a lowercase letter?
- __ j(above, &fail);
+#ifndef ENABLE_LATIN_1
+ __ j(above, &fail); // Weren't letters anyway.
+#else
+ Label convert_capture;
+ __ j(below_equal, &convert_capture); // In range 'a'-'z'.
+ // Latin-1: Check for values in range [224,254] but not 247.
+ __ sub(ecx, Immediate(224 - 'a'));
+ __ cmp(ecx, Immediate(254 - 224));
+ __ j(above, &fail); // Weren't Latin-1 letters.
+ __ cmp(ecx, Immediate(247 - 224)); // Check for 247.
+ __ j(equal, &fail);
+ __ bind(&convert_capture);
+#endif
// Also convert capture character.
__ movzx_b(ecx, Operand(edx, 0));
__ or_(ecx, 0x20);
@@ -569,7 +581,7 @@
Label* on_bit_set) {
__ mov(eax, Immediate(table));
Register index = current_character();
- if (mode_ != ASCII || kTableMask != String::kMaxAsciiCharCode) {
+ if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) {
__ mov(ebx, kTableSize - 1);
__ and_(ebx, current_character());
index = ebx;
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 7834627..2129be3 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -2947,7 +2947,7 @@
__ jmp(miss_ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
+ return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
}
@@ -3440,7 +3440,7 @@
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
+ return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
}
diff --git a/src/ic.cc b/src/ic.cc
index 3633036..0db9aa5 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -43,9 +43,10 @@
char IC::TransitionMarkFromState(IC::State state) {
switch (state) {
case UNINITIALIZED: return '0';
- case PREMONOMORPHIC: return 'P';
+ case PREMONOMORPHIC: return '.';
case MONOMORPHIC: return '1';
case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
+ case POLYMORPHIC: return 'P';
case MEGAMORPHIC: return IsGeneric() ? 'G' : 'N';
// We never see the debugger states here, because the state is
@@ -273,7 +274,7 @@
if (info->pc() == addr) return info->rmode();
}
UNREACHABLE();
- return RelocInfo::NONE;
+ return RelocInfo::NONE32;
}
@@ -712,7 +713,6 @@
// Compute the number of arguments.
int argc = target()->arguments_count();
- bool had_proto_failure = false;
Handle<Code> code;
if (state == UNINITIALIZED) {
// This is the first time we execute this inline cache.
@@ -729,7 +729,7 @@
TryRemoveInvalidPrototypeDependentStub(target(),
*object,
*name)) {
- had_proto_failure = true;
+ state = MONOMORPHIC_PROTOTYPE_FAILURE;
code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
object, name);
} else {
@@ -745,22 +745,39 @@
if (code.is_null()) return;
// Patch the call site depending on the state of the cache.
- if (state == UNINITIALIZED ||
- state == PREMONOMORPHIC ||
- state == MONOMORPHIC ||
- state == MONOMORPHIC_PROTOTYPE_FAILURE) {
- set_target(*code);
- } else if (state == MEGAMORPHIC) {
- // Cache code holding map should be consistent with
- // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
- Handle<JSObject> cache_object = object->IsJSObject()
- ? Handle<JSObject>::cast(object)
- : Handle<JSObject>(JSObject::cast(object->GetPrototype()));
- // Update the stub cache.
- isolate()->stub_cache()->Set(*name, cache_object->map(), *code);
+ switch (state) {
+ case UNINITIALIZED:
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ case PREMONOMORPHIC:
+ set_target(*code);
+ break;
+ case MONOMORPHIC:
+ if (code->ic_state() != MONOMORPHIC) {
+ Map* map = target()->FindFirstMap();
+ if (map != NULL) {
+ isolate()->stub_cache()->Set(*name, map, target());
+ }
+ }
+ set_target(*code);
+ break;
+ case MEGAMORPHIC: {
+ // Cache code holding map should be consistent with
+ // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
+ Handle<JSObject> cache_object = object->IsJSObject()
+ ? Handle<JSObject>::cast(object)
+ : Handle<JSObject>(JSObject::cast(object->GetPrototype()));
+ // Update the stub cache.
+ isolate()->stub_cache()->Set(*name, cache_object->map(), *code);
+ break;
+ }
+ case DEBUG_BREAK:
+ case DEBUG_PREPARE_STEP_IN:
+ break;
+ case POLYMORPHIC:
+ UNREACHABLE();
+ break;
}
- if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
name, state, target());
}
@@ -1024,25 +1041,37 @@
}
// Patch the call site depending on the state of the cache.
- if (state == UNINITIALIZED ||
- state == PREMONOMORPHIC ||
- state == MONOMORPHIC_PROTOTYPE_FAILURE) {
- set_target(*code);
- } else if (state == MONOMORPHIC) {
- // We are transitioning from monomorphic to megamorphic case.
- // Place the current monomorphic stub and stub compiled for
- // the receiver into stub cache.
- Map* map = target()->FindFirstMap();
- if (map != NULL) {
- isolate()->stub_cache()->Set(*name, map, target());
- }
- isolate()->stub_cache()->Set(*name, receiver->map(), *code);
+ switch (state) {
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ set_target(*code);
+ break;
+ case MONOMORPHIC:
+ if (target() != *code) {
+ // We are transitioning from monomorphic to megamorphic case.
+ // Place the current monomorphic stub and stub compiled for
+ // the receiver into stub cache.
+ Map* map = target()->FindFirstMap();
+ if (map != NULL) {
+ isolate()->stub_cache()->Set(*name, map, target());
+ }
+ isolate()->stub_cache()->Set(*name, receiver->map(), *code);
- set_target(*megamorphic_stub());
- } else if (state == MEGAMORPHIC) {
- // Cache code holding map should be consistent with
- // GenerateMonomorphicCacheProbe.
- isolate()->stub_cache()->Set(*name, receiver->map(), *code);
+ set_target(*megamorphic_stub());
+ }
+ break;
+ case MEGAMORPHIC:
+ // Cache code holding map should be consistent with
+ // GenerateMonomorphicCacheProbe.
+ isolate()->stub_cache()->Set(*name, receiver->map(), *code);
+ break;
+ case DEBUG_BREAK:
+ case DEBUG_PREPARE_STEP_IN:
+ break;
+ case POLYMORPHIC:
+ UNREACHABLE();
+ break;
}
TRACE_IC("LoadIC", name, state, target());
@@ -1080,7 +1109,7 @@
receiver_maps, &handler_ics);
isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
PROFILE(isolate(),
- CodeCreateEvent(Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG, *code, 0));
+ CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0));
return code;
}
@@ -1108,7 +1137,7 @@
MaybeObject* KeyedLoadIC::Load(State state,
Handle<Object> object,
Handle<Object> key,
- bool force_generic_stub) {
+ ICMissMode miss_mode) {
// Check for values that can be converted into a symbol directly or
// is representable as a smi.
key = TryConvertKey(key, isolate());
@@ -1209,7 +1238,7 @@
if (use_ic) {
Handle<Code> stub = generic_stub();
- if (!force_generic_stub) {
+ if (miss_mode != MISS_FORCE_GENERIC) {
if (object->IsString() && key->IsNumber()) {
if (state == UNINITIALIZED) {
stub = string_stub();
@@ -1296,13 +1325,26 @@
}
}
- // Patch the call site depending on the state of the cache. Make
- // sure to always rewrite from monomorphic to megamorphic.
- ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
- if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
- set_target(*code);
- } else if (state == MONOMORPHIC) {
- set_target(*megamorphic_stub());
+ // Patch the call site depending on the state of the cache.
+ switch (state) {
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case POLYMORPHIC:
+ set_target(*code);
+ break;
+ case MONOMORPHIC:
+ // Only move to megamorphic if the target changes.
+ if (target() != *code) {
+ set_target(*megamorphic_stub());
+ }
+ break;
+ case MEGAMORPHIC:
+ case DEBUG_BREAK:
+ case DEBUG_PREPARE_STEP_IN:
+ break;
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ UNREACHABLE();
+ break;
}
TRACE_IC("KeyedLoadIC", name, state, target());
@@ -1547,18 +1589,38 @@
}
// Patch the call site depending on the state of the cache.
- if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
- set_target(*code);
- } else if (state == MONOMORPHIC) {
- // Only move to megamorphic if the target changes.
- if (target() != *code) {
- set_target((strict_mode == kStrictMode)
- ? megamorphic_stub_strict()
- : megamorphic_stub());
- }
- } else if (state == MEGAMORPHIC) {
- // Update the stub cache.
- isolate()->stub_cache()->Set(*name, receiver->map(), *code);
+ switch (state) {
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ set_target(*code);
+ break;
+ case MONOMORPHIC:
+ // Only move to megamorphic if the target changes.
+ if (target() != *code) {
+ // We are transitioning from monomorphic to megamorphic case.
+ // Place the current monomorphic stub and stub compiled for
+ // the receiver into stub cache.
+ Map* map = target()->FindFirstMap();
+ if (map != NULL) {
+ isolate()->stub_cache()->Set(*name, map, target());
+ }
+ isolate()->stub_cache()->Set(*name, receiver->map(), *code);
+ set_target((strict_mode == kStrictMode)
+ ? megamorphic_stub_strict()
+ : megamorphic_stub());
+ }
+ break;
+ case MEGAMORPHIC:
+ // Update the stub cache.
+ isolate()->stub_cache()->Set(*name, receiver->map(), *code);
+ break;
+ case DEBUG_BREAK:
+ case DEBUG_PREPARE_STEP_IN:
+ break;
+ case POLYMORPHIC:
+ UNREACHABLE();
+ break;
}
TRACE_IC("StoreIC", name, state, target());
@@ -1585,18 +1647,30 @@
if (!string_stub().is_null() && stub.is_identical_to(string_stub())) {
return result->Add(isolate()->factory()->string_map());
} else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
- if (stub->ic_state() == MONOMORPHIC) {
- result->Add(Handle<Map>(stub->FindFirstMap()));
- } else {
- ASSERT(stub->ic_state() == MEGAMORPHIC);
- AssertNoAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Handle<Object> object(info->target_object());
- ASSERT(object->IsMap());
- AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
+ switch (stub->ic_state()) {
+ case MONOMORPHIC:
+ result->Add(Handle<Map>(stub->FindFirstMap()));
+ break;
+ case POLYMORPHIC: {
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+ for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ Handle<Object> object(info->target_object());
+ ASSERT(object->IsMap());
+ AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
+ }
+ break;
}
+ case MEGAMORPHIC:
+ break;
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ case DEBUG_BREAK:
+ case DEBUG_PREPARE_STEP_IN:
+ UNREACHABLE();
+ break;
}
}
}
@@ -1686,7 +1760,7 @@
isolate()->factory()->polymorphic_code_cache();
Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode,
strict_mode);
- Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, extra_state);
+ Code::Flags flags = Code::ComputeFlags(kind(), POLYMORPHIC, extra_state);
Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -1804,7 +1878,7 @@
receiver_maps, &handler_ics, &transitioned_maps);
isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
PROFILE(isolate(),
- CodeCreateEvent(Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG, *code, 0));
+ CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
return code;
}
@@ -1880,7 +1954,7 @@
Handle<Object> object,
Handle<Object> key,
Handle<Object> value,
- bool force_generic) {
+ ICMissMode miss_mode) {
// Check for values that can be converted into a symbol directly or
// is representable as a smi.
key = TryConvertKey(key, isolate());
@@ -1942,7 +2016,7 @@
if (receiver->elements()->map() ==
isolate()->heap()->non_strict_arguments_elements_map()) {
stub = non_strict_arguments_stub();
- } else if (!force_generic) {
+ } else if (miss_mode != MISS_FORCE_GENERIC) {
if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
StubKind stub_kind = GetStubKind(receiver, key, value);
stub = ComputeStub(receiver, stub_kind, strict_mode, stub);
@@ -2024,15 +2098,28 @@
ASSERT(!code.is_null());
- // Patch the call site depending on the state of the cache. Make
- // sure to always rewrite from monomorphic to megamorphic.
- ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
- if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
- set_target(*code);
- } else if (state == MONOMORPHIC) {
- set_target((strict_mode == kStrictMode)
- ? *megamorphic_stub_strict()
- : *megamorphic_stub());
+ // Patch the call site depending on the state of the cache.
+ switch (state) {
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case POLYMORPHIC:
+ set_target(*code);
+ break;
+ case MONOMORPHIC:
+ // Only move to megamorphic if the target changes.
+ if (target() != *code) {
+ set_target((strict_mode == kStrictMode)
+ ? *megamorphic_stub_strict()
+ : *megamorphic_stub());
+ }
+ break;
+ case MEGAMORPHIC:
+ case DEBUG_BREAK:
+ case DEBUG_PREPARE_STEP_IN:
+ break;
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ UNREACHABLE();
+ break;
}
TRACE_IC("KeyedStoreIC", name, state, target());
@@ -2057,13 +2144,12 @@
extra_ic_state,
args.at<Object>(0),
args.at<String>(1));
- // Result could be a function or a failure.
- JSFunction* raw_function = NULL;
+ JSFunction* raw_function;
if (!maybe_result->To(&raw_function)) return maybe_result;
// The first time the inline cache is updated may be the first time the
- // function it references gets called. If the function is lazily compiled
- // then the first call will trigger a compilation. We check for this case
+ // function it references gets called. If the function is lazily compiled
+ // then the first call will trigger a compilation. We check for this case
// and we do the compilation immediately, instead of waiting for the stub
// currently attached to the JSFunction object to trigger compilation.
if (raw_function->is_compiled()) return raw_function;
@@ -2110,7 +2196,7 @@
ASSERT(args.length() == 2);
KeyedLoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
- return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false);
+ return ic.Load(state, args.at<Object>(0), args.at<Object>(1), MISS);
}
@@ -2119,7 +2205,10 @@
ASSERT(args.length() == 2);
KeyedLoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
- return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true);
+ return ic.Load(state,
+ args.at<Object>(0),
+ args.at<Object>(1),
+ MISS_FORCE_GENERIC);
}
@@ -2211,7 +2300,7 @@
args.at<Object>(0),
args.at<Object>(1),
args.at<Object>(2),
- false);
+ MISS);
}
@@ -2244,7 +2333,7 @@
args.at<Object>(0),
args.at<Object>(1),
args.at<Object>(2),
- true);
+ MISS_FORCE_GENERIC);
}
diff --git a/src/ic.h b/src/ic.h
index bfccd10..dd81ab4 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -476,6 +476,12 @@
};
+enum ICMissMode {
+ MISS_FORCE_GENERIC,
+ MISS
+};
+
+
class KeyedLoadIC: public KeyedIC {
public:
explicit KeyedLoadIC(Isolate* isolate) : KeyedIC(isolate) {
@@ -485,16 +491,16 @@
MUST_USE_RESULT MaybeObject* Load(State state,
Handle<Object> object,
Handle<Object> key,
- bool force_generic_stub);
+ ICMissMode force_generic);
// Code generator routines.
- static void GenerateMiss(MacroAssembler* masm, bool force_generic);
+ static void GenerateMiss(MacroAssembler* masm, ICMissMode force_generic);
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
static void GenerateInitialize(MacroAssembler* masm) {
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
static void GeneratePreMonomorphic(MacroAssembler* masm) {
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
static void GenerateGeneric(MacroAssembler* masm);
static void GenerateString(MacroAssembler* masm);
@@ -654,13 +660,13 @@
Handle<Object> object,
Handle<Object> name,
Handle<Object> value,
- bool force_generic);
+ ICMissMode force_generic);
// Code generators for stub routines. Only called once at startup.
static void GenerateInitialize(MacroAssembler* masm) {
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
- static void GenerateMiss(MacroAssembler* masm, bool force_generic);
+ static void GenerateMiss(MacroAssembler* masm, ICMissMode force_generic);
static void GenerateSlow(MacroAssembler* masm);
static void GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictModeFlag strict_mode);
@@ -686,7 +692,7 @@
StrictModeFlag strict_mode,
KeyedAccessGrowMode grow_mode);
- private:
+ private:
// Update the inline cache.
void UpdateCaches(LookupResult* lookup,
State state,
@@ -848,6 +854,8 @@
enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
+DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss);
+
} } // namespace v8::internal
#endif // V8_IC_H_
diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc
index 3a92b84..5abeb5a 100644
--- a/src/interpreter-irregexp.cc
+++ b/src/interpreter-irregexp.cc
@@ -68,7 +68,7 @@
int from,
int current,
int len,
- Vector<const char> subject) {
+ Vector<const uint8_t> subject) {
for (int i = 0; i < len; i++) {
unsigned int old_char = subject[from++];
unsigned int new_char = subject[current++];
@@ -617,7 +617,7 @@
uc16 previous_char = '\n';
String::FlatContent subject_content = subject->GetFlatContent();
if (subject_content.IsAscii()) {
- Vector<const char> subject_vector = subject_content.ToAsciiVector();
+ Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
if (start_position != 0) previous_char = subject_vector[start_position - 1];
return RawMatch(isolate,
code_base,
diff --git a/src/isolate.cc b/src/isolate.cc
index 60e3379..c136069 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -536,14 +536,15 @@
unsigned int magic2) {
const int kMaxStackTraceSize = 8192;
Handle<String> trace = StackTraceString();
- char buffer[kMaxStackTraceSize];
+ uint8_t buffer[kMaxStackTraceSize];
int length = Min(kMaxStackTraceSize - 1, trace->length());
String::WriteToFlat(*trace, buffer, 0, length);
buffer[length] = '\0';
+ // TODO(dcarney): convert buffer to utf8?
OS::PrintError("Stacktrace (%x-%x) %p %p: %s\n",
magic, magic2,
static_cast<void*>(object), static_cast<void*>(map),
- buffer);
+ reinterpret_cast<char*>(buffer));
OS::Abort();
}
@@ -1344,7 +1345,7 @@
// since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
// set it.
HandleScope scope;
- if (thread_local_top_.pending_exception_ == Failure::OutOfMemoryException()) {
+ if (thread_local_top_.pending_exception_->IsOutOfMemory()) {
context()->mark_out_of_memory();
} else if (thread_local_top_.pending_exception_ ==
heap()->termination_exception()) {
@@ -1375,7 +1376,7 @@
MessageLocation Isolate::GetMessageLocation() {
ASSERT(has_pending_exception());
- if (thread_local_top_.pending_exception_ != Failure::OutOfMemoryException() &&
+ if (!thread_local_top_.pending_exception_->IsOutOfMemory() &&
thread_local_top_.pending_exception_ != heap()->termination_exception() &&
thread_local_top_.has_pending_message_ &&
!thread_local_top_.pending_message_obj_->IsTheHole() &&
@@ -1889,7 +1890,7 @@
if (!external_caught) return;
- if (thread_local_top_.pending_exception_ == Failure::OutOfMemoryException()) {
+ if (thread_local_top_.pending_exception_->IsOutOfMemory()) {
// Do not propagate OOM exception: we should kill VM asap.
} else if (thread_local_top_.pending_exception_ ==
heap()->termination_exception()) {
diff --git a/src/isolate.h b/src/isolate.h
index b3cfb43..8d0575c 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -615,7 +615,7 @@
bool IsExternallyCaught();
bool is_catchable_by_javascript(MaybeObject* exception) {
- return (exception != Failure::OutOfMemoryException()) &&
+ return (!exception->IsOutOfMemory()) &&
(exception != heap()->termination_exception());
}
diff --git a/src/json-parser.h b/src/json-parser.h
index f6140f1..ccb3286 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -441,21 +441,21 @@
int length = position_ - beg_pos;
double number;
if (seq_ascii) {
- Vector<const char> chars(seq_source_->GetChars() + beg_pos, length);
+ Vector<const uint8_t> chars(seq_source_->GetChars() + beg_pos, length);
number = StringToDouble(isolate()->unicode_cache(),
- chars,
+ Vector<const char>::cast(chars),
NO_FLAGS, // Hex, octal or trailing junk.
OS::nan_value());
} else {
- Vector<char> buffer = Vector<char>::New(length);
+ Vector<uint8_t> buffer = Vector<uint8_t>::New(length);
String::WriteToFlat(*source_, buffer.start(), beg_pos, position_);
- Vector<const char> result =
- Vector<const char>(reinterpret_cast<const char*>(buffer.start()),
- length);
+ Vector<const uint8_t> result =
+ Vector<const uint8_t>(buffer.start(), length);
number = StringToDouble(isolate()->unicode_cache(),
- result,
- NO_FLAGS, // Hex, octal or trailing junk.
- 0.0);
+ // TODO(dcarney): Convert StringToDouble to uint_t.
+ Vector<const char>::cast(result),
+ NO_FLAGS, // Hex, octal or trailing junk.
+ 0.0);
buffer.Dispose();
}
SkipWhitespace();
@@ -526,7 +526,7 @@
// in the ASCII sink.
if (sizeof(SinkChar) == kUC16Size ||
seq_ascii ||
- c0_ <= kMaxAsciiCharCode) {
+ c0_ <= String::kMaxOneByteCharCode) {
SeqStringSet(seq_str, count++, c0_);
Advance();
} else {
@@ -566,7 +566,8 @@
}
value = value * 16 + digit;
}
- if (sizeof(SinkChar) == kUC16Size || value <= kMaxAsciiCharCode) {
+ if (sizeof(SinkChar) == kUC16Size ||
+ value <= String::kMaxOneByteCharCode) {
SeqStringSet(seq_str, count++, value);
break;
} else {
@@ -626,9 +627,9 @@
c0_ = c0;
int beg_pos = position_;
position_ = position;
- return SlowScanJsonString<SeqOneByteString, char>(source_,
- beg_pos,
- position_);
+ return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
+ beg_pos,
+ position_);
}
if (c0 < 0x20) return Handle<String>::null();
if (static_cast<uint32_t>(c0) >
@@ -649,7 +650,7 @@
int length = position - position_;
uint32_t hash = (length <= String::kMaxHashCalcLength)
? StringHasher::GetHashCore(running_hash) : length;
- Vector<const char> string_vector(
+ Vector<const uint8_t> string_vector(
seq_source_->GetChars() + position_, length);
SymbolTable* symbol_table = isolate()->heap()->symbol_table();
uint32_t capacity = symbol_table->Capacity();
@@ -662,7 +663,7 @@
break;
}
if (element != isolate()->heap()->the_hole_value() &&
- String::cast(element)->IsAsciiEqualTo(string_vector)) {
+ String::cast(element)->IsOneByteEqualTo(string_vector)) {
// Lookup success, update the current position.
position_ = position;
// Advance past the last '"'.
@@ -679,7 +680,7 @@
// Check for control character (0x00-0x1f) or unterminated string (<0).
if (c0_ < 0x20) return Handle<String>::null();
if (c0_ != '\\') {
- if (seq_ascii || c0_ <= kMaxAsciiCharCode) {
+ if (seq_ascii || c0_ <= String::kMaxOneByteCharCode) {
Advance();
} else {
return SlowScanJsonString<SeqTwoByteString, uc16>(source_,
@@ -687,9 +688,9 @@
position_);
}
} else {
- return SlowScanJsonString<SeqOneByteString, char>(source_,
- beg_pos,
- position_);
+ return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
+ beg_pos,
+ position_);
}
} while (c0_ != '"');
int length = position_ - beg_pos;
@@ -698,7 +699,7 @@
result = factory()->LookupOneByteSymbol(seq_source_, beg_pos, length);
} else {
result = factory()->NewRawOneByteString(length, pretenure_);
- char* dest = SeqOneByteString::cast(*result)->GetChars();
+ uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
String::WriteToFlat(*source_, dest, beg_pos, position_);
}
ASSERT_EQ('"', c0_);
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index 426a370..cec9844 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -60,7 +60,7 @@
template <bool is_ascii, typename Char>
INLINE(void Append_(const Char* chars));
- INLINE(void Append(char c)) {
+ INLINE(void Append(uint8_t c)) {
if (is_ascii_) {
Append_<true>(c);
} else {
@@ -68,11 +68,11 @@
}
}
- INLINE(void Append(const char* chars)) {
+ INLINE(void AppendAscii(const char* chars)) {
if (is_ascii_) {
- Append_<true>(chars);
+ Append_<true>(reinterpret_cast<const uint8_t*>(chars));
} else {
- Append_<false>(chars);
+ Append_<false>(reinterpret_cast<const uint8_t*>(chars));
}
}
@@ -327,15 +327,15 @@
switch (Oddball::cast(*object)->kind()) {
case Oddball::kFalse:
if (deferred_string_key) SerializeDeferredKey(comma, key);
- Append("false");
+ AppendAscii("false");
return SUCCESS;
case Oddball::kTrue:
if (deferred_string_key) SerializeDeferredKey(comma, key);
- Append("true");
+ AppendAscii("true");
return SUCCESS;
case Oddball::kNull:
if (deferred_string_key) SerializeDeferredKey(comma, key);
- Append("null");
+ AppendAscii("null");
return SUCCESS;
default:
return UNCHANGED;
@@ -412,7 +412,7 @@
ASSERT(class_name == isolate_->heap()->Boolean_symbol());
Object* value = JSValue::cast(*object)->value();
ASSERT(value->IsBoolean());
- Append(value->IsTrue() ? "true" : "false");
+ AppendAscii(value->IsTrue() ? "true" : "false");
}
return SUCCESS;
}
@@ -422,7 +422,7 @@
static const int kBufferSize = 100;
char chars[kBufferSize];
Vector<char> buffer(chars, kBufferSize);
- Append(IntToCString(object->value(), buffer));
+ AppendAscii(IntToCString(object->value(), buffer));
return SUCCESS;
}
@@ -430,13 +430,13 @@
BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
double number) {
if (isinf(number) || isnan(number)) {
- Append("null");
+ AppendAscii("null");
return SUCCESS;
}
static const int kBufferSize = 100;
char chars[kBufferSize];
Vector<char> buffer(chars, kBufferSize);
- Append(DoubleToCString(number, buffer));
+ AppendAscii(DoubleToCString(number, buffer));
return SUCCESS;
}
@@ -476,7 +476,7 @@
SerializeElement(Handle<Object>(elements->get(i), isolate_), i);
if (result == SUCCESS) continue;
if (result == UNCHANGED) {
- Append("null");
+ AppendAscii("null");
} else {
return result;
}
@@ -505,12 +505,12 @@
if (i > 0) Append(',');
Handle<Object> element = Object::GetElement(object, i);
if (element->IsUndefined()) {
- Append("null");
+ AppendAscii("null");
} else {
Result result = SerializeElement(element, i);
if (result == SUCCESS) continue;
if (result == UNCHANGED) {
- Append("null");
+ AppendAscii("null");
} else {
return result;
}
@@ -682,8 +682,9 @@
if (DoNotEscape(c)) {
Append_<is_ascii, Char>(c);
} else {
- Append_<is_ascii, char>(
- &JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
+ Append_<is_ascii, uint8_t>(
+ reinterpret_cast<const uint8_t*>(
+ &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
}
// If GC moved the string, we need to refresh the vector.
if (*string != string_location) {
@@ -693,27 +694,22 @@
}
}
- Append_<is_ascii, char>('"');
+ Append_<is_ascii, uint8_t>('"');
}
-template <>
-bool BasicJsonStringifier::DoNotEscape(char c) {
- return c >= '#' && c <= '~' && c != '\\';
-}
-
-
-template <>
-bool BasicJsonStringifier::DoNotEscape(uc16 c) {
+template <typename Char>
+bool BasicJsonStringifier::DoNotEscape(Char c) {
return (c >= 0x80) || (c >= '#' && c <= '~' && c != '\\');
}
template <>
-Vector<const char> BasicJsonStringifier::GetCharVector(Handle<String> string) {
+Vector<const uint8_t> BasicJsonStringifier::GetCharVector(
+ Handle<String> string) {
String::FlatContent flat = string->GetFlatContent();
ASSERT(flat.IsAscii());
- return flat.ToAsciiVector();
+ return flat.ToOneByteVector();
}
@@ -730,14 +726,14 @@
String::FlatContent flat = object->GetFlatContent();
if (is_ascii_) {
if (flat.IsAscii()) {
- SerializeString_<true, char>(object);
+ SerializeString_<true, uint8_t>(object);
} else {
ChangeEncoding();
SerializeString(object);
}
} else {
if (flat.IsAscii()) {
- SerializeString_<false, char>(object);
+ SerializeString_<false, uint8_t>(object);
} else {
SerializeString_<false, uc16>(object);
}
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 813208c..a3efb85 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -309,16 +309,16 @@
index = (needle_content.IsAscii()
? (subject_content.IsAscii()
? SearchString(isolate,
- subject_content.ToAsciiVector(),
- needle_content.ToAsciiVector(),
+ subject_content.ToOneByteVector(),
+ needle_content.ToOneByteVector(),
index)
: SearchString(isolate,
subject_content.ToUC16Vector(),
- needle_content.ToAsciiVector(),
+ needle_content.ToOneByteVector(),
index))
: (subject_content.IsAscii()
? SearchString(isolate,
- subject_content.ToAsciiVector(),
+ subject_content.ToOneByteVector(),
needle_content.ToUC16Vector(),
index)
: SearchString(isolate,
@@ -1681,7 +1681,7 @@
letters[0] = character;
length = 1;
}
- if (!ascii_subject || character <= String::kMaxAsciiCharCode) {
+ if (!ascii_subject || character <= String::kMaxOneByteCharCode) {
return length;
}
// The standard requires that non-ASCII characters cannot have ASCII
@@ -1732,7 +1732,7 @@
bool checked = false;
// We handle the length > 1 case in a later pass.
if (length == 1) {
- if (ascii && c > String::kMaxAsciiCharCodeU) {
+ if (ascii && c > String::kMaxOneByteCharCodeU) {
// Can't match - see above.
return false; // Bounds not checked.
}
@@ -1753,7 +1753,7 @@
Label* on_failure) {
uc16 char_mask;
if (ascii) {
- char_mask = String::kMaxAsciiCharCode;
+ char_mask = String::kMaxOneByteCharCode;
} else {
char_mask = String::kMaxUtf16CodeUnit;
}
@@ -2007,7 +2007,7 @@
// range with a single not-taken branch, speeding up this important
// character range (even non-ASCII charset-based text has spaces and
// punctuation).
- if (*border - 1 > String::kMaxAsciiCharCode && // ASCII case.
+ if (*border - 1 > String::kMaxOneByteCharCode && // ASCII case.
end_index - start_index > (*new_start_index - start_index) * 2 &&
last - first > kSize * 2 &&
binary_chop_index > *new_start_index &&
@@ -2211,7 +2211,7 @@
int max_char;
if (ascii) {
- max_char = String::kMaxAsciiCharCode;
+ max_char = String::kMaxOneByteCharCode;
} else {
max_char = String::kMaxUtf16CodeUnit;
}
@@ -2513,7 +2513,7 @@
bool found_useful_op = false;
uint32_t char_mask;
if (asc) {
- char_mask = String::kMaxAsciiCharCode;
+ char_mask = String::kMaxOneByteCharCode;
} else {
char_mask = String::kMaxUtf16CodeUnit;
}
@@ -2522,7 +2522,7 @@
int char_shift = 0;
for (int i = 0; i < characters_; i++) {
Position* pos = &positions_[i];
- if ((pos->mask & String::kMaxAsciiCharCode) != 0) {
+ if ((pos->mask & String::kMaxOneByteCharCode) != 0) {
found_useful_op = true;
}
mask_ |= (pos->mask & char_mask) << char_shift;
@@ -2565,7 +2565,7 @@
// load so the value is already masked down.
uint32_t char_mask;
if (compiler->ascii()) {
- char_mask = String::kMaxAsciiCharCode;
+ char_mask = String::kMaxOneByteCharCode;
} else {
char_mask = String::kMaxUtf16CodeUnit;
}
@@ -2575,7 +2575,11 @@
// For 2-character preloads in ASCII mode or 1-character preloads in
// TWO_BYTE mode we also use a 16 bit load with zero extend.
if (details->characters() == 2 && compiler->ascii()) {
- if ((mask & 0x7f7f) == 0x7f7f) need_mask = false;
+#ifndef ENABLE_LATIN_1
+ if ((mask & 0x7f7f) == 0xffff) need_mask = false;
+#else
+ if ((mask & 0xffff) == 0xffff) need_mask = false;
+#endif
} else if (details->characters() == 1 && !compiler->ascii()) {
if ((mask & 0xffff) == 0xffff) need_mask = false;
} else {
@@ -2617,7 +2621,7 @@
int characters = details->characters();
int char_mask;
if (compiler->ascii()) {
- char_mask = String::kMaxAsciiCharCode;
+ char_mask = String::kMaxOneByteCharCode;
} else {
char_mask = String::kMaxUtf16CodeUnit;
}
@@ -2834,24 +2838,24 @@
};
-RegExpNode* SeqRegExpNode::FilterASCII(int depth) {
+RegExpNode* SeqRegExpNode::FilterASCII(int depth, bool ignore_case) {
if (info()->replacement_calculated) return replacement();
if (depth < 0) return this;
ASSERT(!info()->visited);
VisitMarker marker(info());
- return FilterSuccessor(depth - 1);
+ return FilterSuccessor(depth - 1, ignore_case);
}
-RegExpNode* SeqRegExpNode::FilterSuccessor(int depth) {
- RegExpNode* next = on_success_->FilterASCII(depth - 1);
+RegExpNode* SeqRegExpNode::FilterSuccessor(int depth, bool ignore_case) {
+ RegExpNode* next = on_success_->FilterASCII(depth - 1, ignore_case);
if (next == NULL) return set_replacement(NULL);
on_success_ = next;
return set_replacement(this);
}
-RegExpNode* TextNode::FilterASCII(int depth) {
+RegExpNode* TextNode::FilterASCII(int depth, bool ignore_case) {
if (info()->replacement_calculated) return replacement();
if (depth < 0) return this;
ASSERT(!info()->visited);
@@ -2862,15 +2866,40 @@
if (elm.type == TextElement::ATOM) {
Vector<const uc16> quarks = elm.data.u_atom->data();
for (int j = 0; j < quarks.length(); j++) {
- // We don't need special handling for case independence
- // because of the rule that case independence cannot make
- // a non-ASCII character match an ASCII character.
- if (quarks[j] > String::kMaxAsciiCharCode) {
+#ifndef ENABLE_LATIN_1
+ if (quarks[j] > String::kMaxOneByteCharCode) {
return set_replacement(NULL);
}
+#else
+ if (quarks[j] <= String::kMaxOneByteCharCode) continue;
+ if (!ignore_case) return set_replacement(NULL);
+ // Here, we need to check for characters whose upper and lower cases
+ // are outside the Latin-1 range.
+ // TODO(dcarney): Replace this code with a simple
+ // table lookup in unibrow::Latin-1.
+ // TODO(dcarney): Test cases!.
+ unibrow::uchar result;
+ int chars;
+ chars = unibrow::ToLowercase::Convert(quarks[j], 0, &result, NULL);
+ if (chars > 1 ||
+ (chars == 1 && result <= String::kMaxOneByteCharCodeU)) {
+ continue;
+ }
+ chars = unibrow::ToUppercase::Convert(quarks[j], 0, &result, NULL);
+ if (chars > 1 ||
+ (chars == 1 && result <= String::kMaxOneByteCharCodeU)) {
+ continue;
+ }
+ // This character is definitely not in the Latin-1 range.
+ return set_replacement(NULL);
+#endif
}
} else {
ASSERT(elm.type == TextElement::CHAR_CLASS);
+#ifdef ENABLE_LATIN_1
+ // TODO(dcarney): Can this be improved?
+ if (ignore_case) continue;
+#endif
RegExpCharacterClass* cc = elm.data.u_char_class;
ZoneList<CharacterRange>* ranges = cc->ranges(zone());
if (!CharacterRange::IsCanonical(ranges)) {
@@ -2881,39 +2910,40 @@
if (cc->is_negated()) {
if (range_count != 0 &&
ranges->at(0).from() == 0 &&
- ranges->at(0).to() >= String::kMaxAsciiCharCode) {
+ ranges->at(0).to() >= String::kMaxOneByteCharCode) {
return set_replacement(NULL);
}
} else {
if (range_count == 0 ||
- ranges->at(0).from() > String::kMaxAsciiCharCode) {
+ ranges->at(0).from() > String::kMaxOneByteCharCode) {
return set_replacement(NULL);
}
}
}
}
- return FilterSuccessor(depth - 1);
+ return FilterSuccessor(depth - 1, ignore_case);
}
-RegExpNode* LoopChoiceNode::FilterASCII(int depth) {
+RegExpNode* LoopChoiceNode::FilterASCII(int depth, bool ignore_case) {
if (info()->replacement_calculated) return replacement();
if (depth < 0) return this;
if (info()->visited) return this;
{
VisitMarker marker(info());
- RegExpNode* continue_replacement = continue_node_->FilterASCII(depth - 1);
+ RegExpNode* continue_replacement =
+ continue_node_->FilterASCII(depth - 1, ignore_case);
// If we can't continue after the loop then there is no sense in doing the
// loop.
if (continue_replacement == NULL) return set_replacement(NULL);
}
- return ChoiceNode::FilterASCII(depth - 1);
+ return ChoiceNode::FilterASCII(depth - 1, ignore_case);
}
-RegExpNode* ChoiceNode::FilterASCII(int depth) {
+RegExpNode* ChoiceNode::FilterASCII(int depth, bool ignore_case) {
if (info()->replacement_calculated) return replacement();
if (depth < 0) return this;
if (info()->visited) return this;
@@ -2932,7 +2962,8 @@
RegExpNode* survivor = NULL;
for (int i = 0; i < choice_count; i++) {
GuardedAlternative alternative = alternatives_->at(i);
- RegExpNode* replacement = alternative.node()->FilterASCII(depth - 1);
+ RegExpNode* replacement =
+ alternative.node()->FilterASCII(depth - 1, ignore_case);
ASSERT(replacement != this); // No missing EMPTY_MATCH_CHECK.
if (replacement != NULL) {
alternatives_->at(i).set_node(replacement);
@@ -2952,7 +2983,7 @@
new(zone()) ZoneList<GuardedAlternative>(surviving, zone());
for (int i = 0; i < choice_count; i++) {
RegExpNode* replacement =
- alternatives_->at(i).node()->FilterASCII(depth - 1);
+ alternatives_->at(i).node()->FilterASCII(depth - 1, ignore_case);
if (replacement != NULL) {
alternatives_->at(i).set_node(replacement);
new_alternatives->Add(alternatives_->at(i), zone());
@@ -2963,7 +2994,8 @@
}
-RegExpNode* NegativeLookaheadChoiceNode::FilterASCII(int depth) {
+RegExpNode* NegativeLookaheadChoiceNode::FilterASCII(int depth,
+ bool ignore_case) {
if (info()->replacement_calculated) return replacement();
if (depth < 0) return this;
if (info()->visited) return this;
@@ -2971,12 +3003,12 @@
// Alternative 0 is the negative lookahead, alternative 1 is what comes
// afterwards.
RegExpNode* node = alternatives_->at(1).node();
- RegExpNode* replacement = node->FilterASCII(depth - 1);
+ RegExpNode* replacement = node->FilterASCII(depth - 1, ignore_case);
if (replacement == NULL) return set_replacement(NULL);
alternatives_->at(1).set_node(replacement);
RegExpNode* neg_node = alternatives_->at(0).node();
- RegExpNode* neg_replacement = neg_node->FilterASCII(depth - 1);
+ RegExpNode* neg_replacement = neg_node->FilterASCII(depth - 1, ignore_case);
// If the negative lookahead is always going to fail then
// we don't need to check it.
if (neg_replacement == NULL) return set_replacement(replacement);
@@ -3299,7 +3331,7 @@
switch (pass) {
case NON_ASCII_MATCH:
ASSERT(ascii);
- if (quarks[j] > String::kMaxAsciiCharCode) {
+ if (quarks[j] > String::kMaxOneByteCharCode) {
assembler->GoTo(backtrack);
return;
}
@@ -3498,7 +3530,7 @@
if (ranges->length() != 1) return NULL;
uint32_t max_char;
if (compiler->ascii()) {
- max_char = String::kMaxAsciiCharCode;
+ max_char = String::kMaxOneByteCharCode;
} else {
max_char = String::kMaxUtf16CodeUnit;
}
@@ -3698,7 +3730,7 @@
: length_(length),
compiler_(compiler) {
if (compiler->ascii()) {
- max_char_ = String::kMaxAsciiCharCode;
+ max_char_ = String::kMaxOneByteCharCode;
} else {
max_char_ = String::kMaxUtf16CodeUnit;
}
@@ -5337,8 +5369,8 @@
uc16 bottom = from();
uc16 top = to();
if (is_ascii) {
- if (bottom > String::kMaxAsciiCharCode) return;
- if (top > String::kMaxAsciiCharCode) top = String::kMaxAsciiCharCode;
+ if (bottom > String::kMaxOneByteCharCode) return;
+ if (top > String::kMaxOneByteCharCode) top = String::kMaxOneByteCharCode;
}
unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
if (top == bottom) {
@@ -5885,7 +5917,7 @@
int length = GetCaseIndependentLetters(
ISOLATE,
character,
- bm->max_char() == String::kMaxAsciiCharCode,
+ bm->max_char() == String::kMaxOneByteCharCode,
chars);
for (int j = 0; j < length; j++) {
bm->Set(offset, chars[j]);
@@ -6099,10 +6131,12 @@
}
}
if (is_ascii) {
- node = node->FilterASCII(RegExpCompiler::kMaxRecursion);
+ node = node->FilterASCII(RegExpCompiler::kMaxRecursion, ignore_case);
// Do it again to propagate the new nodes to places where they were not
// put because they had not been calculated yet.
- if (node != NULL) node = node->FilterASCII(RegExpCompiler::kMaxRecursion);
+ if (node != NULL) {
+ node = node->FilterASCII(RegExpCompiler::kMaxRecursion, ignore_case);
+ }
}
if (node == NULL) node = new(zone) EndNode(EndNode::BACKTRACK, zone);
diff --git a/src/jsregexp.h b/src/jsregexp.h
index 96825ce..7e83d42 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -628,7 +628,7 @@
// If we know that the input is ASCII then there are some nodes that can
// never match. This method returns a node that can be substituted for
// itself, or NULL if the node can never match.
- virtual RegExpNode* FilterASCII(int depth) { return this; }
+ virtual RegExpNode* FilterASCII(int depth, bool ignore_case) { return this; }
// Helper for FilterASCII.
RegExpNode* replacement() {
ASSERT(info()->replacement_calculated);
@@ -723,7 +723,7 @@
: RegExpNode(on_success->zone()), on_success_(on_success) { }
RegExpNode* on_success() { return on_success_; }
void set_on_success(RegExpNode* node) { on_success_ = node; }
- virtual RegExpNode* FilterASCII(int depth);
+ virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
@@ -735,7 +735,7 @@
}
protected:
- RegExpNode* FilterSuccessor(int depth);
+ RegExpNode* FilterSuccessor(int depth, bool ignore_case);
private:
RegExpNode* on_success_;
@@ -861,7 +861,7 @@
BoyerMooreLookahead* bm,
bool not_at_start);
void CalculateOffsets();
- virtual RegExpNode* FilterASCII(int depth);
+ virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
private:
enum TextEmitPassType {
@@ -1097,7 +1097,7 @@
void set_not_at_start() { not_at_start_ = true; }
void set_being_calculated(bool b) { being_calculated_ = b; }
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
- virtual RegExpNode* FilterASCII(int depth);
+ virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
protected:
int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
@@ -1155,7 +1155,7 @@
// characters, but on a negative lookahead the negative branch did not take
// part in that calculation (EatsAtLeast) so the assumptions don't hold.
virtual bool try_to_emit_quick_check_for_alternative(int i) { return i != 0; }
- virtual RegExpNode* FilterASCII(int depth);
+ virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
};
@@ -1185,7 +1185,7 @@
RegExpNode* continue_node() { return continue_node_; }
bool body_can_be_zero_length() { return body_can_be_zero_length_; }
virtual void Accept(NodeVisitor* visitor);
- virtual RegExpNode* FilterASCII(int depth);
+ virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
private:
// AddAlternative is made private for loop nodes because alternatives
diff --git a/src/lithium-allocator.h b/src/lithium-allocator.h
index 0dd192d..9ea6641 100644
--- a/src/lithium-allocator.h
+++ b/src/lithium-allocator.h
@@ -399,40 +399,6 @@
};
-class GrowableBitVector BASE_EMBEDDED {
- public:
- GrowableBitVector() : bits_(NULL) { }
-
- bool Contains(int value) const {
- if (!InBitsRange(value)) return false;
- return bits_->Contains(value);
- }
-
- void Add(int value, Zone* zone) {
- EnsureCapacity(value, zone);
- bits_->Add(value);
- }
-
- private:
- static const int kInitialLength = 1024;
-
- bool InBitsRange(int value) const {
- return bits_ != NULL && bits_->length() > value;
- }
-
- void EnsureCapacity(int value, Zone* zone) {
- if (InBitsRange(value)) return;
- int new_length = bits_ == NULL ? kInitialLength : bits_->length();
- while (new_length <= value) new_length *= 2;
- BitVector* new_bits = new(zone) BitVector(new_length, zone);
- if (bits_ != NULL) new_bits->CopyFrom(*bits_);
- bits_ = new_bits;
- }
-
- BitVector* bits_;
-};
-
-
class LAllocator BASE_EMBEDDED {
public:
LAllocator(int first_virtual_register, HGraph* graph);
diff --git a/src/log.cc b/src/log.cc
index 88527ca..efbb8f7 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -384,7 +384,10 @@
if (str == NULL) return;
if (str->HasOnlyAsciiChars()) {
int utf8_length = Min(str->length(), kUtf8BufferSize - utf8_pos_);
- String::WriteToFlat(str, utf8_buffer_ + utf8_pos_, 0, utf8_length);
+ String::WriteToFlat(str,
+ reinterpret_cast<uint8_t*>(utf8_buffer_ + utf8_pos_),
+ 0,
+ utf8_length);
utf8_pos_ += utf8_length;
return;
}
@@ -393,7 +396,7 @@
int previous = unibrow::Utf16::kNoPreviousCharacter;
for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
uc16 c = utf16_buffer[i];
- if (c <= String::kMaxAsciiCharCodeU) {
+ if (c <= unibrow::Utf8::kMaxOneByteChar) {
utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
} else {
int char_length = unibrow::Utf8::Length(c, previous);
diff --git a/src/log.h b/src/log.h
index eced605..b5b6817 100644
--- a/src/log.h
+++ b/src/log.h
@@ -127,10 +127,10 @@
V(EVAL_TAG, "Eval") \
V(FUNCTION_TAG, "Function") \
V(KEYED_LOAD_IC_TAG, "KeyedLoadIC") \
- V(KEYED_LOAD_MEGAMORPHIC_IC_TAG, "KeyedLoadMegamorphicIC") \
+ V(KEYED_LOAD_POLYMORPHIC_IC_TAG, "KeyedLoadPolymorphicIC") \
V(KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG, "KeyedExternalArrayLoadIC") \
V(KEYED_STORE_IC_TAG, "KeyedStoreIC") \
- V(KEYED_STORE_MEGAMORPHIC_IC_TAG, "KeyedStoreMegamorphicIC") \
+ V(KEYED_STORE_POLYMORPHIC_IC_TAG, "KeyedStorePolymorphicIC") \
V(KEYED_EXTERNAL_ARRAY_STORE_IC_TAG, "KeyedExternalArrayStoreIC") \
V(LAZY_COMPILE_TAG, "LazyCompile") \
V(LOAD_IC_TAG, "LoadIC") \
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 8ca14db..3ebdb1e 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -1689,10 +1689,10 @@
for (;
cell_index < last_cell_index;
cell_index++, cell_base += 32 * kPointerSize) {
- ASSERT((unsigned)cell_index ==
- Bitmap::IndexToCell(
- Bitmap::CellAlignIndex(
- p->AddressToMarkbitIndex(cell_base))));
+ ASSERT(static_cast<unsigned>(cell_index) ==
+ Bitmap::IndexToCell(
+ Bitmap::CellAlignIndex(
+ p->AddressToMarkbitIndex(cell_base))));
const MarkBit::CellType current_cell = cells[cell_index];
if (current_cell == 0) continue;
@@ -2589,10 +2589,10 @@
for (;
cell_index < last_cell_index;
cell_index++, cell_base += 32 * kPointerSize) {
- ASSERT((unsigned)cell_index ==
- Bitmap::IndexToCell(
- Bitmap::CellAlignIndex(
- p->AddressToMarkbitIndex(cell_base))));
+ ASSERT(static_cast<unsigned>(cell_index) ==
+ Bitmap::IndexToCell(
+ Bitmap::CellAlignIndex(
+ p->AddressToMarkbitIndex(cell_base))));
if (cells[cell_index] == 0) continue;
int live_objects = MarkWordToObjectStarts(cells[cell_index], offsets);
@@ -2762,10 +2762,10 @@
for (;
cell_index < last_cell_index;
cell_index++, object_address += 32 * kPointerSize) {
- ASSERT((unsigned)cell_index ==
- Bitmap::IndexToCell(
- Bitmap::CellAlignIndex(
- p->AddressToMarkbitIndex(object_address))));
+ ASSERT(static_cast<unsigned>(cell_index) ==
+ Bitmap::IndexToCell(
+ Bitmap::CellAlignIndex(
+ p->AddressToMarkbitIndex(object_address))));
int live_objects = MarkWordToObjectStarts(cells[cell_index], offsets);
int live_index = 0;
for ( ; live_objects != 0; live_objects--) {
@@ -3442,10 +3442,10 @@
for ( ;
cell_index < last_cell_index;
cell_index++, block_address += 32 * kPointerSize) {
- ASSERT((unsigned)cell_index ==
- Bitmap::IndexToCell(
- Bitmap::CellAlignIndex(
- p->AddressToMarkbitIndex(block_address))));
+ ASSERT(static_cast<unsigned>(cell_index) ==
+ Bitmap::IndexToCell(
+ Bitmap::CellAlignIndex(
+ p->AddressToMarkbitIndex(block_address))));
uint32_t cell = cells[cell_index];
if (cell != 0) {
// We have a live object. Check approximately whether it is more than 32
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index caf544f..38a7cf0 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -66,7 +66,7 @@
Operand::Operand(Smi* value) {
rm_ = no_reg;
imm32_ = reinterpret_cast<intptr_t>(value);
- rmode_ = RelocInfo::NONE;
+ rmode_ = RelocInfo::NONE32;
}
@@ -80,9 +80,36 @@
}
+int Register::NumAllocatableRegisters() {
+ if (CpuFeatures::IsSupported(FPU)) {
+ return kMaxNumAllocatableRegisters;
+ } else {
+ return kMaxNumAllocatableRegisters - kGPRsPerNonFPUDouble;
+ }
+}
+
+
+int DoubleRegister::NumRegisters() {
+ if (CpuFeatures::IsSupported(FPU)) {
+ return FPURegister::kNumRegisters;
+ } else {
+ return 1;
+ }
+}
+
+
+int DoubleRegister::NumAllocatableRegisters() {
+ if (CpuFeatures::IsSupported(FPU)) {
+ return FPURegister::kMaxNumAllocatableRegisters;
+ } else {
+ return 1;
+ }
+}
+
+
int FPURegister::ToAllocationIndex(FPURegister reg) {
ASSERT(reg.code() % 2 == 0);
- ASSERT(reg.code() / 2 < kNumAllocatableRegisters);
+ ASSERT(reg.code() / 2 < kMaxNumAllocatableRegisters);
ASSERT(reg.is_valid());
ASSERT(!reg.is(kDoubleRegZero));
ASSERT(!reg.is(kLithiumScratchDouble));
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index de97bc3..1ca4d52 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -73,6 +73,33 @@
}
+const char* DoubleRegister::AllocationIndexToString(int index) {
+ if (CpuFeatures::IsSupported(FPU)) {
+ ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
+ const char* const names[] = {
+ "f0",
+ "f2",
+ "f4",
+ "f6",
+ "f8",
+ "f10",
+ "f12",
+ "f14",
+ "f16",
+ "f18",
+ "f20",
+ "f22",
+ "f24",
+ "f26"
+ };
+ return names[index];
+ } else {
+ ASSERT(index == 0);
+ return "sfpd0";
+ }
+}
+
+
void CpuFeatures::Probe() {
unsigned standard_features = (OS::CpuFeaturesImpliedByPlatform() |
CpuFeaturesImpliedByCompiler());
@@ -221,7 +248,7 @@
} else {
// No relocation needed.
imm32_ = reinterpret_cast<intptr_t>(obj);
- rmode_ = RelocInfo::NONE;
+ rmode_ = RelocInfo::NONE32;
}
}
@@ -556,7 +583,7 @@
int32_t Assembler::GetBranchOffset(Instr instr) {
ASSERT(IsBranch(instr));
- return ((int16_t)(instr & kImm16Mask)) << 2;
+ return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
}
@@ -689,7 +716,7 @@
Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
ASSERT(IsOri(instr_ori));
- uint32_t imm = (uint32_t)buffer_ + target_pos;
+ uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
ASSERT((imm & 3) == 0);
instr_lui &= ~kImm16Mask;
@@ -700,7 +727,7 @@
instr_at_put(pos + 1 * Assembler::kInstrSize,
instr_ori | (imm & kImm16Mask));
} else {
- uint32_t imm28 = (uint32_t)buffer_ + target_pos;
+ uint32_t imm28 = reinterpret_cast<uint32_t>(buffer_) + target_pos;
imm28 &= kImm28Mask;
ASSERT((imm28 & 3) == 0);
@@ -849,6 +876,20 @@
void Assembler::GenInstrRegister(Opcode opcode,
+ FPURegister fr,
+ FPURegister ft,
+ FPURegister fs,
+ FPURegister fd,
+ SecondaryField func) {
+ ASSERT(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
+ ASSERT(CpuFeatures::IsEnabled(FPU));
+ Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
+ | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
+ emit(instr);
+}
+
+
+void Assembler::GenInstrRegister(Opcode opcode,
SecondaryField fmt,
Register rt,
FPURegister fs,
@@ -952,7 +993,7 @@
}
}
- uint32_t imm = (uint32_t)buffer_ + target_pos;
+ uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
ASSERT((imm & 3) == 0);
return imm;
@@ -1087,7 +1128,8 @@
#if DEBUG
// Get pc of delay slot.
uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
- bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+ bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
+ (kImm26Bits + kImmFieldShift)) == 0;
ASSERT(in_range && ((target & 3) == 0));
#endif
GenInstrJump(J, target >> 2);
@@ -1108,7 +1150,8 @@
#ifdef DEBUG
// Get pc of delay slot.
uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
- bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+ bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
+ (kImm26Bits + kImmFieldShift)) == 0;
ASSERT(in_range && ((target & 3) == 0));
#endif
positions_recorder()->WriteRecordedPositions();
@@ -1127,8 +1170,8 @@
void Assembler::j_or_jr(int32_t target, Register rs) {
// Get pc of delay slot.
uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
- bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
-
+ bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
+ (kImm26Bits + kImmFieldShift)) == 0;
if (in_range) {
j(target);
} else {
@@ -1140,8 +1183,8 @@
void Assembler::jal_or_jalr(int32_t target, Register rs) {
// Get pc of delay slot.
uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
- bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
-
+ bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
+ (kImm26Bits+kImmFieldShift)) == 0;
if (in_range) {
jal(target);
} else {
@@ -1651,6 +1694,12 @@
}
+void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
+ FPURegister ft) {
+ GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
+}
+
+
void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
}
@@ -1900,7 +1949,7 @@
return 2; // Number of instructions patched.
} else {
uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
- if ((int32_t)imm28 == kEndOfJumpChain) {
+ if (static_cast<int32_t>(imm28) == kEndOfJumpChain) {
return 0; // Number of instructions patched.
}
imm28 += pc_delta;
@@ -2150,9 +2199,10 @@
Instr instr3 = instr_at(pc + 2 * kInstrSize);
uint32_t ipc = reinterpret_cast<uint32_t>(pc + 3 * kInstrSize);
- bool in_range =
- ((uint32_t)(ipc ^ itarget) >> (kImm26Bits + kImmFieldShift)) == 0;
- uint32_t target_field = (uint32_t)(itarget & kJumpAddrMask) >> kImmFieldShift;
+ bool in_range = (ipc ^ static_cast<uint32_t>(itarget) >>
+ (kImm26Bits + kImmFieldShift)) == 0;
+ uint32_t target_field =
+ static_cast<uint32_t>(itarget & kJumpAddrMask) >>kImmFieldShift;
bool patched_jump = false;
#ifndef ALLOW_JAL_IN_BOUNDARY_REGION
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index 75d110a..1bde0b6 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -72,20 +72,23 @@
// Core register.
struct Register {
static const int kNumRegisters = v8::internal::kNumRegisters;
- static const int kNumAllocatableRegisters = 14; // v0 through t7.
+ static const int kMaxNumAllocatableRegisters = 14; // v0 through t7.
static const int kSizeInBytes = 4;
+ static const int kGPRsPerNonFPUDouble = 2;
+
+ inline static int NumAllocatableRegisters();
static int ToAllocationIndex(Register reg) {
return reg.code() - 2; // zero_reg and 'at' are skipped.
}
static Register FromAllocationIndex(int index) {
- ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
return from_code(index + 2); // zero_reg and 'at' are skipped.
}
static const char* AllocationIndexToString(int index) {
- ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
const char* const names[] = {
"v0",
"v1",
@@ -197,38 +200,19 @@
// f28: 0.0
// f30: scratch register.
static const int kNumReservedRegisters = 2;
- static const int kNumAllocatableRegisters = kNumRegisters / 2 -
+ static const int kMaxNumAllocatableRegisters = kNumRegisters / 2 -
kNumReservedRegisters;
-
+ inline static int NumRegisters();
+ inline static int NumAllocatableRegisters();
inline static int ToAllocationIndex(FPURegister reg);
+ static const char* AllocationIndexToString(int index);
static FPURegister FromAllocationIndex(int index) {
- ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
return from_code(index * 2);
}
- static const char* AllocationIndexToString(int index) {
- ASSERT(index >= 0 && index < kNumAllocatableRegisters);
- const char* const names[] = {
- "f0",
- "f2",
- "f4",
- "f6",
- "f8",
- "f10",
- "f12",
- "f14",
- "f16",
- "f18",
- "f20",
- "f22",
- "f24",
- "f26"
- };
- return names[index];
- }
-
static FPURegister from_code(int code) {
FPURegister r = { code };
return r;
@@ -316,6 +300,9 @@
const FPURegister f30 = { 30 };
const FPURegister f31 = { 31 };
+const Register sfpd_lo = { kRegister_t6_Code };
+const Register sfpd_hi = { kRegister_t7_Code };
+
// Register aliases.
// cp is assumed to be a callee saved register.
// Defined using #define instead of "static const Register&" because Clang
@@ -361,7 +348,7 @@
public:
// Immediate.
INLINE(explicit Operand(int32_t immediate,
- RelocInfo::Mode rmode = RelocInfo::NONE));
+ RelocInfo::Mode rmode = RelocInfo::NONE32));
INLINE(explicit Operand(const ExternalReference& f));
INLINE(explicit Operand(const char* s));
INLINE(explicit Operand(Object** opp));
@@ -818,6 +805,7 @@
void add_d(FPURegister fd, FPURegister fs, FPURegister ft);
void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
void abs_d(FPURegister fd, FPURegister fs);
void mov_d(FPURegister fd, FPURegister fs);
@@ -1159,6 +1147,13 @@
SecondaryField func = NULLSF);
void GenInstrRegister(Opcode opcode,
+ FPURegister fr,
+ FPURegister ft,
+ FPURegister fs,
+ FPURegister fd,
+ SecondaryField func = NULLSF);
+
+ void GenInstrRegister(Opcode opcode,
SecondaryField fmt,
Register rt,
FPURegister fs,
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index b2348fc..793968e 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -1297,6 +1297,26 @@
#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
+void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+
+ // Preserve registers across notification, this is important for compiled
+ // stubs that tail call the runtime on deopts passing their parameters in
+ // registers.
+ __ MultiPush(kJSCallerSaved | kCalleeSaved);
+ // Pass the function and deoptimization type to the runtime system.
+ __ CallRuntime(Runtime::kNotifyStubFailure, 0);
+ __ MultiPop(kJSCallerSaved | kCalleeSaved);
+ }
+
+ __ mov(at, ra); // Stash the miss continuation
+ __ Addu(sp, sp, Operand(kPointerSize)); // Ignore state
+ __ pop(ra); // Restore RA to continuation in JSFunction
+ __ Jump(at); // Jump to miss handler
+}
+
+
static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
Deoptimizer::BailoutType type) {
{
@@ -1413,7 +1433,7 @@
// a0: actual number of arguments
// a1: function
Label shift_arguments;
- __ li(t0, Operand(0, RelocInfo::NONE)); // Indicate regular JS_FUNCTION.
+ __ li(t0, Operand(0, RelocInfo::NONE32)); // Indicate regular JS_FUNCTION.
{ Label convert_to_object, use_global_receiver, patch_receiver;
// Change context eagerly in case we need the global receiver.
__ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
@@ -1467,7 +1487,7 @@
__ sll(at, a0, kPointerSizeLog2);
__ addu(at, sp, at);
__ lw(a1, MemOperand(at));
- __ li(t0, Operand(0, RelocInfo::NONE));
+ __ li(t0, Operand(0, RelocInfo::NONE32));
__ Branch(&patch_receiver);
// Use the global receiver object from the called function as the
@@ -1490,11 +1510,11 @@
// 3b. Check for function proxy.
__ bind(&slow);
- __ li(t0, Operand(1, RelocInfo::NONE)); // Indicate function proxy.
+ __ li(t0, Operand(1, RelocInfo::NONE32)); // Indicate function proxy.
__ Branch(&shift_arguments, eq, a2, Operand(JS_FUNCTION_PROXY_TYPE));
__ bind(&non_function);
- __ li(t0, Operand(2, RelocInfo::NONE)); // Indicate non-function.
+ __ li(t0, Operand(2, RelocInfo::NONE32)); // Indicate non-function.
// 3c. Patch the first argument when calling a non-function. The
// CALL_NON_FUNCTION builtin expects the non-function callee as
@@ -1725,7 +1745,7 @@
__ bind(&call_proxy);
__ push(a1); // Add function proxy as last argument.
__ Addu(a0, a0, Operand(1));
- __ li(a2, Operand(0, RelocInfo::NONE));
+ __ li(a2, Operand(0, RelocInfo::NONE32));
__ SetCallKind(t1, CALL_AS_METHOD);
__ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY);
__ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index a05cee8..3d01be6 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -38,6 +38,17 @@
namespace internal {
+void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { a1, a0 };
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(KeyedLoadIC_Miss);
+}
+
+
#define __ ACCESS_MASM(masm)
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
@@ -332,6 +343,7 @@
MacroAssembler* masm,
int length,
FastCloneShallowArrayStub::Mode mode,
+ AllocationSiteInfoMode allocation_site_info_mode,
Label* fail) {
// Registers on entry:
// a3: boilerplate literal array.
@@ -344,7 +356,12 @@
? FixedDoubleArray::SizeFor(length)
: FixedArray::SizeFor(length);
}
- int size = JSArray::kSize + elements_size;
+ int size = JSArray::kSize;
+ int allocation_info_start = size;
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ size += AllocationSiteInfo::kSize;
+ }
+ size += elements_size;
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
@@ -355,6 +372,13 @@
fail,
TAG_OBJECT);
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ li(a2, Operand(Handle<Map>(masm->isolate()->heap()->
+ allocation_site_info_map())));
+ __ sw(a2, FieldMemOperand(v0, allocation_info_start));
+ __ sw(a3, FieldMemOperand(v0, allocation_info_start + kPointerSize));
+ }
+
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length == 0)) {
@@ -367,7 +391,11 @@
// Get hold of the elements array of the boilerplate and setup the
// elements pointer in the resulting object.
__ lw(a3, FieldMemOperand(a3, JSArray::kElementsOffset));
- __ Addu(a2, v0, Operand(JSArray::kSize));
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ Addu(a2, v0, Operand(JSArray::kSize + AllocationSiteInfo::kSize));
+ } else {
+ __ Addu(a2, v0, Operand(JSArray::kSize));
+ }
__ sw(a2, FieldMemOperand(v0, JSArray::kElementsOffset));
// Copy the elements array.
@@ -396,6 +424,12 @@
__ Branch(&slow_case, eq, a3, Operand(t1));
FastCloneShallowArrayStub::Mode mode = mode_;
+ AllocationSiteInfoMode allocation_site_info_mode =
+ DONT_TRACK_ALLOCATION_SITE_INFO;
+ if (mode == CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO) {
+ mode = CLONE_ANY_ELEMENTS;
+ allocation_site_info_mode = TRACK_ALLOCATION_SITE_INFO;
+ }
if (mode == CLONE_ANY_ELEMENTS) {
Label double_elements, check_fast_elements;
__ lw(v0, FieldMemOperand(a3, JSArray::kElementsOffset));
@@ -403,7 +437,9 @@
__ LoadRoot(t1, Heap::kFixedCOWArrayMapRootIndex);
__ Branch(&check_fast_elements, ne, v0, Operand(t1));
GenerateFastCloneShallowArrayCommon(masm, 0,
- COPY_ON_WRITE_ELEMENTS, &slow_case);
+ COPY_ON_WRITE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
// Return and remove the on-stack parameters.
__ DropAndRet(3);
@@ -411,7 +447,9 @@
__ LoadRoot(t1, Heap::kFixedArrayMapRootIndex);
__ Branch(&double_elements, ne, v0, Operand(t1));
GenerateFastCloneShallowArrayCommon(masm, length_,
- CLONE_ELEMENTS, &slow_case);
+ CLONE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
// Return and remove the on-stack parameters.
__ DropAndRet(3);
@@ -442,7 +480,8 @@
__ pop(a3);
}
- GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
+ GenerateFastCloneShallowArrayCommon(masm, length_, mode,
+ allocation_site_info_mode, &slow_case);
// Return and remove the on-stack parameters.
__ DropAndRet(3);
@@ -500,7 +539,7 @@
// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
// scratch register. Destroys the source register. No GC occurs during this
// stub so you don't have to set up the frame.
-class ConvertToDoubleStub : public CodeStub {
+class ConvertToDoubleStub : public PlatformCodeStub {
public:
ConvertToDoubleStub(Register result_reg_1,
Register result_reg_2,
@@ -3893,12 +3932,29 @@
void CodeStub::GenerateFPStubs() {
- CEntryStub save_doubles(1, kSaveFPRegs);
- Handle<Code> code = save_doubles.GetCode();
- code->set_is_pregenerated(true);
- StoreBufferOverflowStub stub(kSaveFPRegs);
- stub.GetCode()->set_is_pregenerated(true);
- code->GetIsolate()->set_fp_stubs_generated(true);
+ SaveFPRegsMode mode = CpuFeatures::IsSupported(FPU)
+ ? kSaveFPRegs
+ : kDontSaveFPRegs;
+ CEntryStub save_doubles(1, mode);
+ StoreBufferOverflowStub stub(mode);
+ // These stubs might already be in the snapshot, detect that and don't
+ // regenerate, which would lead to code stub initialization state being messed
+ // up.
+ Code* save_doubles_code = NULL;
+ Code* store_buffer_overflow_code = NULL;
+ if (!save_doubles.FindCodeInCache(&save_doubles_code, ISOLATE)) {
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope2(FPU);
+ save_doubles_code = *save_doubles.GetCode();
+ store_buffer_overflow_code = *stub.GetCode();
+ } else {
+ save_doubles_code = *save_doubles.GetCode();
+ store_buffer_overflow_code = *stub.GetCode();
+ }
+ save_doubles_code->set_is_pregenerated(true);
+ store_buffer_overflow_code->set_is_pregenerated(true);
+ }
+ ISOLATE->set_fp_stubs_generated(true);
}
@@ -4109,7 +4165,7 @@
Isolate* isolate = masm->isolate();
ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
isolate);
- __ li(a0, Operand(false, RelocInfo::NONE));
+ __ li(a0, Operand(false, RelocInfo::NONE32));
__ li(a2, Operand(external_caught));
__ sw(a0, MemOperand(a2));
@@ -5538,8 +5594,8 @@
// Check for function proxy.
__ Branch(&non_function, ne, a3, Operand(JS_FUNCTION_PROXY_TYPE));
__ push(a1); // Put proxy as additional argument.
- __ li(a0, Operand(argc_ + 1, RelocInfo::NONE));
- __ li(a2, Operand(0, RelocInfo::NONE));
+ __ li(a0, Operand(argc_ + 1, RelocInfo::NONE32));
+ __ li(a2, Operand(0, RelocInfo::NONE32));
__ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY);
__ SetCallKind(t1, CALL_AS_METHOD);
{
@@ -5596,7 +5652,7 @@
__ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
__ bind(&do_call);
// Set expected number of arguments to zero (not changing r0).
- __ li(a2, Operand(0, RelocInfo::NONE));
+ __ li(a2, Operand(0, RelocInfo::NONE32));
__ SetCallKind(t1, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
@@ -5713,11 +5769,11 @@
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiShiftSize == 0);
- ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
+ ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
__ And(t0,
code_,
Operand(kSmiTagMask |
- ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
+ ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
__ Branch(&slow_case_, ne, t0, Operand(zero_reg));
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index b560c63..356cc87 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -37,7 +37,7 @@
// Compute a transcendental math function natively, or call the
// TranscendentalCache runtime function.
-class TranscendentalCacheStub: public CodeStub {
+class TranscendentalCacheStub: public PlatformCodeStub {
public:
enum ArgumentType {
TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits,
@@ -59,7 +59,7 @@
};
-class StoreBufferOverflowStub: public CodeStub {
+class StoreBufferOverflowStub: public PlatformCodeStub {
public:
explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
: save_doubles_(save_fp) { }
@@ -78,7 +78,7 @@
};
-class UnaryOpStub: public CodeStub {
+class UnaryOpStub: public PlatformCodeStub {
public:
UnaryOpStub(Token::Value op,
UnaryOverwriteMode mode,
@@ -220,7 +220,7 @@
};
-class StringAddStub: public CodeStub {
+class StringAddStub: public PlatformCodeStub {
public:
explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
@@ -243,7 +243,7 @@
};
-class SubStringStub: public CodeStub {
+class SubStringStub: public PlatformCodeStub {
public:
SubStringStub() {}
@@ -255,7 +255,7 @@
};
-class StringCompareStub: public CodeStub {
+class StringCompareStub: public PlatformCodeStub {
public:
StringCompareStub() { }
@@ -296,7 +296,7 @@
// This stub can convert a signed int32 to a heap number (double). It does
// not work for int32s that are in Smi range! No GC occurs during this stub
// so you don't have to set up the frame.
-class WriteInt32ToHeapNumberStub : public CodeStub {
+class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
public:
WriteInt32ToHeapNumberStub(Register the_int,
Register the_heap_number,
@@ -340,7 +340,7 @@
};
-class NumberToStringStub: public CodeStub {
+class NumberToStringStub: public PlatformCodeStub {
public:
NumberToStringStub() { }
@@ -366,7 +366,7 @@
};
-class RecordWriteStub: public CodeStub {
+class RecordWriteStub: public PlatformCodeStub {
public:
RecordWriteStub(Register object,
Register value,
@@ -512,7 +512,7 @@
Register GetRegThatIsNotOneOf(Register r1,
Register r2,
Register r3) {
- for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
+ for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
Register candidate = Register::FromAllocationIndex(i);
if (candidate.is(r1)) continue;
if (candidate.is(r2)) continue;
@@ -571,7 +571,7 @@
// Enter C code from generated RegExp code in a way that allows
// the C code to fix the return address in case of a GC.
// Currently only needed on ARM and MIPS.
-class RegExpCEntryStub: public CodeStub {
+class RegExpCEntryStub: public PlatformCodeStub {
public:
RegExpCEntryStub() {}
virtual ~RegExpCEntryStub() {}
@@ -589,7 +589,7 @@
// keep the code which called into native pinned in the memory. Currently the
// simplest approach is to generate such stub early enough so it can never be
// moved by GC
-class DirectCEntryStub: public CodeStub {
+class DirectCEntryStub: public PlatformCodeStub {
public:
DirectCEntryStub() {}
void Generate(MacroAssembler* masm);
@@ -739,7 +739,7 @@
};
-class StringDictionaryLookupStub: public CodeStub {
+class StringDictionaryLookupStub: public PlatformCodeStub {
public:
enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 1da8089..27835af 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -180,6 +180,10 @@
Register scratch = t6;
+ if (FLAG_track_allocation_sites) {
+ masm->TestJSArrayForAllocationSiteInfo(a2, t0, fail);
+ }
+
// Check for empty arrays, which only require a map transition and no changes
// to the backing store.
__ lw(t0, FieldMemOperand(a2, JSObject::kElementsOffset));
diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h
index 13b0b43..d429443 100644
--- a/src/mips/codegen-mips.h
+++ b/src/mips/codegen-mips.h
@@ -46,6 +46,10 @@
class CodeGenerator: public AstVisitor {
public:
+ CodeGenerator() {
+ InitializeAstVisitor();
+ }
+
static bool MakeCode(CompilationInfo* info);
// Printing of AST, etc. as requested by flags.
@@ -70,7 +74,7 @@
int pos,
bool right_here = false);
- DEFINE_AST_VISITOR_SUBCLASS_METHODS();
+ DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
private:
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
diff --git a/src/mips/constants-mips.cc b/src/mips/constants-mips.cc
index 7d654f6..ddfa891 100644
--- a/src/mips/constants-mips.cc
+++ b/src/mips/constants-mips.cc
@@ -302,6 +302,8 @@
return kRegisterType;
};
break;
+ case COP1X:
+ return kRegisterType;
// 16 bits Immediate type instructions. e.g.: addi dest, src, imm16.
case REGIMM:
case BEQ:
diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
index 3d58571..e7c55f5 100644
--- a/src/mips/constants-mips.h
+++ b/src/mips/constants-mips.h
@@ -99,7 +99,7 @@
// FPU (coprocessor 1) control registers. Currently only FCSR is implemented.
const int kFCSRRegister = 31;
const int kInvalidFPUControlRegister = -1;
-const uint32_t kFPUInvalidResult = (uint32_t) (1 << 31) - 1;
+const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
// FCSR constants.
const uint32_t kFCSRInexactFlagBit = 2;
@@ -216,6 +216,8 @@
// and are therefore shifted by 2.
const int kImmFieldShift = 2;
+const int kFrBits = 5;
+const int kFrShift = 21;
const int kFsShift = 11;
const int kFsBits = 5;
const int kFtShift = 16;
@@ -295,7 +297,9 @@
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
- SDC1 = ((7 << 3) + 5) << kOpcodeShift
+ SDC1 = ((7 << 3) + 5) << kOpcodeShift,
+
+ COP1X = ((1 << 4) + 3) << kOpcodeShift
};
enum SecondaryField {
@@ -416,6 +420,8 @@
CVT_S_L = ((4 << 3) + 0),
CVT_D_L = ((4 << 3) + 1),
// COP1 Encoding of Function Field When rs=PS.
+ // COP1X Encoding of Function Field.
+ MADD_D = ((4 << 3) + 1),
NULLSF = 0
};
@@ -677,6 +683,10 @@
return Bits(kFtShift + kFtBits - 1, kFtShift);
}
+ inline int FrValue() const {
+ return Bits(kFrShift + kFrBits -1, kFrShift);
+ }
+
// Float Compare condition code instruction bits.
inline int FCccValue() const {
return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index a134f59..634aecd 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -75,12 +75,12 @@
Address call_address = code_start_address + deopt_data->Pc(i)->value();
Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry,
- RelocInfo::NONE);
+ RelocInfo::NONE32);
int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
ASSERT(call_size_in_bytes <= patch_size());
CodePatcher patcher(call_address, call_size_in_words);
- patcher.masm()->Call(deopt_entry, RelocInfo::NONE);
+ patcher.masm()->Call(deopt_entry, RelocInfo::NONE32);
ASSERT(prev_call_address == NULL ||
call_address >= prev_call_address + patch_size());
ASSERT(call_address + patch_size() <= code->instruction_end());
@@ -206,7 +206,7 @@
void Deoptimizer::DoComputeOsrOutputFrame() {
DeoptimizationInputData* data = DeoptimizationInputData::cast(
- optimized_code_->deoptimization_data());
+ compiled_code_->deoptimization_data());
unsigned ast_id = data->OsrAstId()->value();
int bailout_id = LookupBailoutId(data, BailoutId(ast_id));
@@ -240,7 +240,7 @@
unsigned input_frame_size = input_->GetFrameSize();
ASSERT(fixed_size + height_in_bytes == input_frame_size);
- unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize;
+ unsigned stack_slot_size = compiled_code_->stack_slots() * kPointerSize;
unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
unsigned outgoing_size = outgoing_height * kPointerSize;
unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
@@ -332,7 +332,7 @@
unsigned pc_offset = data->OsrPcOffset()->value();
uint32_t pc = reinterpret_cast<uint32_t>(
- optimized_code_->entry() + pc_offset);
+ compiled_code_->entry() + pc_offset);
output_[0]->SetPc(pc);
}
Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR);
@@ -445,6 +445,79 @@
}
+void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
+ int frame_index) {
+ //
+ // FROM TO <-fp
+ // | .... | | .... |
+ // +-------------------------+ +-------------------------+
+ // | JSFunction continuation | | parameter 1 |
+ // +-------------------------+ +-------------------------+
+ // | | saved frame (fp) | | .... |
+ // | +=========================+<-fp +-------------------------+
+ // | | JSFunction context | | parameter n |
+ // v +-------------------------+ +-------------------------|
+ // | COMPILED_STUB marker | | JSFunction continuation |
+ // +-------------------------+ +-------------------------+<-sp
+ // | | a0 = number of parameters
+ // | ... | a1 = failure handler address
+ // | | fp = saved frame
+ // +-------------------------+<-sp cp = JSFunction context
+ //
+ //
+
+ ASSERT(compiled_code_->kind() == Code::COMPILED_STUB);
+ int major_key = compiled_code_->major_key();
+ CodeStubInterfaceDescriptor* descriptor =
+ isolate_->code_stub_interface_descriptor(major_key);
+
+ int output_frame_size =
+ (1 + descriptor->register_param_count_) * kPointerSize;
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, 0);
+ Code* notify_failure =
+ isolate_->builtins()->builtin(Builtins::kNotifyStubFailure);
+ output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
+ output_frame->SetContinuation(
+ reinterpret_cast<uint32_t>(notify_failure->entry()));
+
+ Code* code;
+ CEntryStub(1, kSaveFPRegs).FindCodeInCache(&code, isolate_);
+ output_frame->SetPc(reinterpret_cast<intptr_t>(code->instruction_start()));
+ unsigned input_frame_size = input_->GetFrameSize();
+ intptr_t value = input_->GetFrameSlot(input_frame_size - kPointerSize);
+ output_frame->SetFrameSlot(0, value);
+ value = input_->GetFrameSlot(input_frame_size - 2 * kPointerSize);
+ output_frame->SetRegister(fp.code(), value);
+ output_frame->SetFp(value);
+ value = input_->GetFrameSlot(input_frame_size - 3 * kPointerSize);
+ output_frame->SetRegister(cp.code(), value);
+
+ int parameter_offset = kPointerSize * descriptor->register_param_count_;
+ for (int i = 0; i < descriptor->register_param_count_; ++i) {
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ ASSERT(opcode == Translation::REGISTER);
+ USE(opcode);
+ int input_reg = iterator->Next();
+ intptr_t reg_value = input_->GetRegister(input_reg);
+ output_frame->SetFrameSlot(parameter_offset, reg_value);
+ parameter_offset -= kPointerSize;
+ }
+
+ ApiFunction function(descriptor->deoptimization_handler_);
+ ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
+ intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
+ output_frame->SetRegister(s0.code(), descriptor->register_param_count_);
+ output_frame->SetRegister(s1.code(),
+ (descriptor->register_param_count_ - 1) * kPointerSize);
+ output_frame->SetRegister(s2.code(), handler);
+
+ ASSERT(frame_index == 0);
+ output_[frame_index] = output_frame;
+}
+
+
void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
int frame_index) {
Builtins* builtins = isolate_->builtins();
@@ -868,7 +941,7 @@
}
input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
- for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) {
+ for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
input_->SetDoubleRegister(i, 0.0);
}
@@ -889,7 +962,6 @@
Isolate* isolate = masm()->isolate();
- CpuFeatures::Scope scope(FPU);
// Unlike on ARM we don't save all the registers, just the useful ones.
// For the rest, there are gaps on the stack, so the offsets remain the same.
const int kNumberOfRegisters = Register::kNumRegisters;
@@ -898,14 +970,19 @@
RegList saved_regs = restored_regs | sp.bit() | ra.bit();
const int kDoubleRegsSize =
- kDoubleSize * FPURegister::kNumAllocatableRegisters;
+ kDoubleSize * FPURegister::kMaxNumAllocatableRegisters;
- // Save all FPU registers before messing with them.
- __ Subu(sp, sp, Operand(kDoubleRegsSize));
- for (int i = 0; i < FPURegister::kNumAllocatableRegisters; ++i) {
- FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
- int offset = i * kDoubleSize;
- __ sdc1(fpu_reg, MemOperand(sp, offset));
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ // Save all FPU registers before messing with them.
+ __ Subu(sp, sp, Operand(kDoubleRegsSize));
+ for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
+ FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
+ int offset = i * kDoubleSize;
+ __ sdc1(fpu_reg, MemOperand(sp, offset));
+ }
+ } else {
+ __ Subu(sp, sp, Operand(kDoubleRegsSize));
}
// Push saved_regs (needed to populate FrameDescription::registers_).
@@ -977,14 +1054,17 @@
}
}
- // Copy FPU registers to
- // double_registers_[DoubleRegister::kNumAllocatableRegisters]
- int double_regs_offset = FrameDescription::double_registers_offset();
- for (int i = 0; i < FPURegister::kNumAllocatableRegisters; ++i) {
- int dst_offset = i * kDoubleSize + double_regs_offset;
- int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
- __ ldc1(f0, MemOperand(sp, src_offset));
- __ sdc1(f0, MemOperand(a1, dst_offset));
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ // Copy FPU registers to
+ // double_registers_[DoubleRegister::kNumAllocatableRegisters]
+ int double_regs_offset = FrameDescription::double_registers_offset();
+ for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
+ int dst_offset = i * kDoubleSize + double_regs_offset;
+ int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
+ __ ldc1(f0, MemOperand(sp, src_offset));
+ __ sdc1(f0, MemOperand(a1, dst_offset));
+ }
}
// Remove the bailout id, eventually return address, and the saved registers
@@ -1005,11 +1085,14 @@
// frame description.
__ Addu(a3, a1, Operand(FrameDescription::frame_content_offset()));
Label pop_loop;
+ Label pop_loop_header;
+ __ Branch(&pop_loop_header);
__ bind(&pop_loop);
__ pop(t0);
__ sw(t0, MemOperand(a3, 0));
- __ Branch(USE_DELAY_SLOT, &pop_loop, ne, a2, Operand(sp));
- __ addiu(a3, a3, sizeof(uint32_t)); // In delay slot.
+ __ addiu(a3, a3, sizeof(uint32_t));
+ __ bind(&pop_loop_header);
+ __ Branch(&pop_loop, ne, a2, Operand(sp));
// Compute the output frame in the deoptimizer.
__ push(a0); // Preserve deoptimizer object across call.
@@ -1024,25 +1107,30 @@
__ pop(a0); // Restore deoptimizer object (class Deoptimizer).
// Replace the current (input) frame with the output frames.
- Label outer_push_loop, inner_push_loop;
+ Label outer_push_loop, inner_push_loop,
+ outer_loop_header, inner_loop_header;
// Outer loop state: a0 = current "FrameDescription** output_",
// a1 = one past the last FrameDescription**.
__ lw(a1, MemOperand(a0, Deoptimizer::output_count_offset()));
__ lw(a0, MemOperand(a0, Deoptimizer::output_offset())); // a0 is output_.
__ sll(a1, a1, kPointerSizeLog2); // Count to offset.
__ addu(a1, a0, a1); // a1 = one past the last FrameDescription**.
+ __ jmp(&outer_loop_header);
__ bind(&outer_push_loop);
// Inner loop state: a2 = current FrameDescription*, a3 = loop index.
__ lw(a2, MemOperand(a0, 0)); // output_[ix]
__ lw(a3, MemOperand(a2, FrameDescription::frame_size_offset()));
+ __ jmp(&inner_loop_header);
__ bind(&inner_push_loop);
__ Subu(a3, a3, Operand(sizeof(uint32_t)));
__ Addu(t2, a2, Operand(a3));
__ lw(t3, MemOperand(t2, FrameDescription::frame_content_offset()));
__ push(t3);
+ __ bind(&inner_loop_header);
__ Branch(&inner_push_loop, ne, a3, Operand(zero_reg));
__ Addu(a0, a0, Operand(kPointerSize));
+ __ bind(&outer_loop_header);
__ Branch(&outer_push_loop, lt, a0, Operand(a1));
diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc
index 1d40c2c..0eca71f 100644
--- a/src/mips/disasm-mips.cc
+++ b/src/mips/disasm-mips.cc
@@ -350,6 +350,10 @@
int reg = instr->FdValue();
PrintFPURegister(reg);
return 2;
+ } else if (format[1] == 'r') { // 'fr: fr register.
+ int reg = instr->FrValue();
+ PrintFPURegister(reg);
+ return 2;
}
UNREACHABLE();
return -1;
@@ -618,6 +622,15 @@
UNREACHABLE();
}
break;
+ case COP1X:
+ switch (instr->FunctionFieldRaw()) {
+ case MADD_D:
+ Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
+ break;
+ default:
+ UNREACHABLE();
+ };
+ break;
case SPECIAL:
switch (instr->FunctionFieldRaw()) {
case JR:
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 5bc5162..d4390b2 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -147,7 +147,7 @@
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
- info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+ info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
__ stop("stop-at");
}
#endif
@@ -675,7 +675,7 @@
Label* fall_through) {
if (CpuFeatures::IsSupported(FPU)) {
ToBooleanStub stub(result_register());
- __ CallStub(&stub);
+ __ CallStub(&stub, condition->test_id());
__ mov(at, zero_reg);
} else {
// Call the runtime to find the boolean value of the source and then
@@ -1744,6 +1744,15 @@
FastCloneShallowArrayStub::Mode mode = has_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
: FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
+
+ // Tracking allocation info allows us to pre-transition later if it makes
+ // sense.
+ if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS &&
+ FLAG_track_allocation_sites) {
+ mode = FastCloneShallowArrayStub::
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO;
+ }
+
FastCloneShallowArrayStub stub(mode, length);
__ CallStub(&stub);
}
@@ -2353,7 +2362,7 @@
CallFunctionStub stub(arg_count, flags);
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
- __ CallStub(&stub);
+ __ CallStub(&stub, expr->CallFeedbackId());
RecordJSReturnSite(expr);
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index 4ac92af..0f9d687 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -858,7 +858,7 @@
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a2);
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -893,7 +893,7 @@
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0); // (In delay slot) return the value stored in v0.
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -926,7 +926,7 @@
Object* KeyedLoadIC_Miss(Arguments args);
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
// ---------- S t a t e --------------
// -- ra : return address
// -- a0 : key
@@ -939,7 +939,7 @@
__ Push(a1, a0);
// Perform tail call to the entry.
- ExternalReference ref = force_generic
+ ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
: ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
@@ -1166,7 +1166,7 @@
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -1452,11 +1452,11 @@
IC_Utility(kKeyedLoadPropertyWithInterceptor), masm->isolate()), 2, 1);
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
// ---------- S t a t e --------------
// -- a0 : value
// -- a1 : key
@@ -1467,7 +1467,7 @@
// Push receiver, key and value for runtime call.
__ Push(a2, a1, a0);
- ExternalReference ref = force_generic
+ ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
@@ -1703,7 +1703,7 @@
// was inlined.
Instr instr = Assembler::instr_at(andi_instruction_address);
return Assembler::IsAndImmediate(instr) &&
- Assembler::GetRt(instr) == (uint32_t)zero_reg.code();
+ Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code());
}
@@ -1715,7 +1715,7 @@
// was inlined.
Instr instr = Assembler::instr_at(andi_instruction_address);
if (!(Assembler::IsAndImmediate(instr) &&
- Assembler::GetRt(instr) == (uint32_t)zero_reg.code())) {
+ Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()))) {
return;
}
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index fd7af9f..02ca145 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -77,6 +77,7 @@
return GeneratePrologue() &&
GenerateBody() &&
GenerateDeferredCode() &&
+ GenerateDeoptJumpTable() &&
GenerateSafepointTable();
}
@@ -116,42 +117,48 @@
bool LCodeGen::GeneratePrologue() {
ASSERT(is_generating());
- ProfileEntryHookStub::MaybeCallEntryHook(masm_);
+ if (info()->IsOptimizing()) {
+ ProfileEntryHookStub::MaybeCallEntryHook(masm_);
#ifdef DEBUG
- if (strlen(FLAG_stop_at) > 0 &&
- info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
- __ stop("stop_at");
- }
+ if (strlen(FLAG_stop_at) > 0 &&
+ info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
+ __ stop("stop_at");
+ }
#endif
- // a1: Callee's JS function.
- // cp: Callee's context.
- // fp: Caller's frame pointer.
- // lr: Caller's pc.
+ // a1: Callee's JS function.
+ // cp: Callee's context.
+ // fp: Caller's frame pointer.
+ // lr: Caller's pc.
- // Strict mode functions and builtins need to replace the receiver
- // with undefined when called as functions (without an explicit
- // receiver object). r5 is zero for method calls and non-zero for
- // function calls.
- if (!info_->is_classic_mode() || info_->is_native()) {
- Label ok;
- __ Branch(&ok, eq, t1, Operand(zero_reg));
+ // Strict mode functions and builtins need to replace the receiver
+ // with undefined when called as functions (without an explicit
+ // receiver object). r5 is zero for method calls and non-zero for
+ // function calls.
+ if (!info_->is_classic_mode() || info_->is_native()) {
+ Label ok;
+ __ Branch(&ok, eq, t1, Operand(zero_reg));
- int receiver_offset = scope()->num_parameters() * kPointerSize;
- __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
- __ sw(a2, MemOperand(sp, receiver_offset));
- __ bind(&ok);
+ int receiver_offset = scope()->num_parameters() * kPointerSize;
+ __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
+ __ sw(a2, MemOperand(sp, receiver_offset));
+ __ bind(&ok);
+ }
}
info()->set_prologue_offset(masm_->pc_offset());
- // The following three instructions must remain together and unmodified for
- // code aging to work properly.
- __ Push(ra, fp, cp, a1);
- // Add unused load of ip to ensure prologue sequence is identical for
- // full-codegen and lithium-codegen.
- __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
- __ Addu(fp, sp, Operand(2 * kPointerSize)); // Adj. FP to point to saved FP.
+ if (NeedsEagerFrame()) {
+ // The following three instructions must remain together and unmodified for
+ // code aging to work properly.
+ __ Push(ra, fp, cp, a1);
+ // Add unused load of ip to ensure prologue sequence is identical for
+ // full-codegen and lithium-codegen.
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+ // Adj. FP to point to saved FP.
+ __ Addu(fp, sp, Operand(2 * kPointerSize));
+ frame_is_built_ = true;
+ }
// Reserve space for the stack slots needed by the code.
int slots = GetStackSlotCount();
@@ -170,7 +177,7 @@
}
// Possibly allocate a local context.
- int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+ int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots > 0) {
Comment(";;; Allocate local context");
// Argument to NewContext is the function, which is in a1.
@@ -206,7 +213,7 @@
}
// Trace the call.
- if (FLAG_trace) {
+ if (FLAG_trace && info()->IsOptimizing()) {
__ CallRuntime(Runtime::kTraceEnter, 0);
}
EnsureSpaceForLazyDeopt();
@@ -264,10 +271,31 @@
for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
LDeferredCode* code = deferred_[i];
__ bind(code->entry());
+ if (NeedsDeferredFrame()) {
+ Comment(";;; Deferred build frame",
+ code->instruction_index(),
+ code->instr()->Mnemonic());
+ ASSERT(!frame_is_built_);
+ ASSERT(info()->IsStub());
+ frame_is_built_ = true;
+ __ MultiPush(cp.bit() | fp.bit() | ra.bit());
+ __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
+ __ push(scratch0());
+ __ Addu(fp, sp, Operand(2 * kPointerSize));
+ }
Comment(";;; Deferred code @%d: %s.",
code->instruction_index(),
code->instr()->Mnemonic());
code->Generate();
+ if (NeedsDeferredFrame()) {
+ Comment(";;; Deferred destroy frame",
+ code->instruction_index(),
+ code->instr()->Mnemonic());
+ ASSERT(frame_is_built_);
+ __ pop(at);
+ __ MultiPop(cp.bit() | fp.bit() | ra.bit());
+ frame_is_built_ = false;
+ }
__ jmp(code->exit());
}
}
@@ -279,10 +307,72 @@
bool LCodeGen::GenerateDeoptJumpTable() {
- // TODO(plind): not clear that this will have advantage for MIPS.
- // Skipping it for now. Raised issue #100 for this.
- Abort("Unimplemented: GenerateDeoptJumpTable");
- return false;
+ // Check that the jump table is accessible from everywhere in the function
+ // code, i.e. that offsets to the table can be encoded in the 16bit signed
+ // immediate of a branch instruction.
+ // To simplify we consider the code size from the first instruction to the
+ // end of the jump table.
+ if (!is_int16((masm()->pc_offset() / Assembler::kInstrSize) +
+ deopt_jump_table_.length() * 12)) {
+ Abort("Generated code is too large");
+ }
+
+ Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
+ __ RecordComment("[ Deoptimization jump table");
+ Label table_start;
+ __ bind(&table_start);
+ Label needs_frame_not_call;
+ Label needs_frame_is_call;
+ for (int i = 0; i < deopt_jump_table_.length(); i++) {
+ __ bind(&deopt_jump_table_[i].label);
+ Address entry = deopt_jump_table_[i].address;
+ __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry)));
+ if (deopt_jump_table_[i].needs_frame) {
+ if (deopt_jump_table_[i].is_lazy_deopt) {
+ if (needs_frame_is_call.is_bound()) {
+ __ Branch(&needs_frame_is_call);
+ } else {
+ __ bind(&needs_frame_is_call);
+ __ MultiPush(cp.bit() | fp.bit() | ra.bit());
+ // This variant of deopt can only be used with stubs. Since we don't
+ // have a function pointer to install in the stack frame that we're
+ // building, install a special marker there instead.
+ ASSERT(info()->IsStub());
+ __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
+ __ push(scratch0());
+ __ Addu(fp, sp, Operand(2 * kPointerSize));
+ __ Call(t9);
+ }
+ } else {
+ if (needs_frame_not_call.is_bound()) {
+ __ Branch(&needs_frame_not_call);
+ } else {
+ __ bind(&needs_frame_not_call);
+ __ MultiPush(cp.bit() | fp.bit() | ra.bit());
+ // This variant of deopt can only be used with stubs. Since we don't
+ // have a function pointer to install in the stack frame that we're
+ // building, install a special marker there instead.
+ ASSERT(info()->IsStub());
+ __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
+ __ push(scratch0());
+ __ Addu(fp, sp, Operand(2 * kPointerSize));
+ __ Jump(t9);
+ }
+ }
+ } else {
+ if (deopt_jump_table_[i].is_lazy_deopt) {
+ __ Call(t9);
+ } else {
+ __ Jump(t9);
+ }
+ }
+ }
+ __ RecordComment("]");
+
+ // The deoptimization jump table is the last part of the instruction
+ // sequence. Mark the generated code as done unless we bailed out.
+ if (!is_aborted()) status_ = DONE;
+ return !is_aborted();
}
@@ -482,7 +572,9 @@
translation,
arguments_index,
arguments_count);
- int closure_id = *info()->closure() != *environment->closure()
+ bool has_closure_id = !info()->closure().is_null() &&
+ *info()->closure() != *environment->closure();
+ int closure_id = has_closure_id
? DefineDeoptimizationLiteral(environment->closure())
: Translation::kSelfLiteralId;
@@ -503,6 +595,9 @@
ASSERT(height == 0);
translation->BeginSetterStubFrame(closure_id);
break;
+ case STUB:
+ translation->BeginCompiledStubFrame();
+ break;
case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
break;
@@ -689,7 +784,11 @@
RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(environment->HasBeenRegistered());
int id = environment->deoptimization_index();
- Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
+
+ Deoptimizer::BailoutType bailout_type = info()->IsStub()
+ ? Deoptimizer::LAZY
+ : Deoptimizer::EAGER;
+ Address entry = Deoptimizer::GetDeoptimizationEntry(id, bailout_type);
if (entry == NULL) {
Abort("bailout was not prepared");
return;
@@ -712,9 +811,22 @@
__ bind(&skip);
}
- // TODO(plind): The Arm port is a little different here, due to their
- // DeOpt jump table, which is not used for Mips yet.
- __ Jump(entry, RelocInfo::RUNTIME_ENTRY, cc, src1, src2);
+ bool needs_lazy_deopt = info()->IsStub();
+ ASSERT(info()->IsStub() || frame_is_built_);
+ if (cc == al && !needs_lazy_deopt) {
+ __ Jump(entry, RelocInfo::RUNTIME_ENTRY, cc, src1, src2);
+ } else {
+ // We often have several deopts to the same entry, reuse the last
+ // jump entry if this is the case.
+ if (deopt_jump_table_.is_empty() ||
+ (deopt_jump_table_.last().address != entry) ||
+ (deopt_jump_table_.last().is_lazy_deopt != needs_lazy_deopt) ||
+ (deopt_jump_table_.last().needs_frame != !frame_is_built_)) {
+ JumpTableEntry table_entry(entry, !frame_is_built_, needs_lazy_deopt);
+ deopt_jump_table_.Add(table_entry, zone());
+ }
+ __ Branch(&deopt_jump_table_.last().label, cc, src1, src2);
+ }
}
@@ -976,6 +1088,14 @@
DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
}
+ // Check for (kMinInt % -1).
+ if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+ Label left_not_min_int;
+ __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
+ DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
+ __ bind(&left_not_min_int);
+ }
+
__ Branch(USE_DELAY_SLOT, &done, ge, left, Operand(zero_reg));
__ mfhi(result);
@@ -1009,7 +1129,7 @@
__ bind(&left_not_zero);
}
- // Check for (-kMinInt / -1).
+ // Check for (kMinInt / -1).
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
Label left_not_min_int;
__ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
@@ -1023,6 +1143,18 @@
}
+void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
+ DoubleRegister addend = ToDoubleRegister(instr->addend());
+ DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
+ DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
+
+ // This is computed in-place.
+ ASSERT(addend.is(ToDoubleRegister(instr->result())));
+
+ __ madd_d(addend, addend, multiplier, multiplicand);
+}
+
+
void LCodeGen::DoMulI(LMulI* instr) {
Register scratch = scratch0();
Register result = ToRegister(instr->result());
@@ -1281,6 +1413,7 @@
void LCodeGen::DoConstantD(LConstantD* instr) {
ASSERT(instr->result()->IsDoubleRegister());
DoubleRegister result = ToDoubleRegister(instr->result());
+ CpuFeatures::Scope scope(FPU);
double v = instr->value();
__ Move(result, v);
}
@@ -1478,6 +1611,7 @@
__ bind(&done);
} else {
ASSERT(instr->hydrogen()->representation().IsDouble());
+ CpuFeatures::Scope scope(FPU);
FPURegister left_reg = ToDoubleRegister(left);
FPURegister right_reg = ToDoubleRegister(right);
FPURegister result_reg = ToDoubleRegister(instr->result());
@@ -1518,6 +1652,7 @@
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister left = ToDoubleRegister(instr->left());
DoubleRegister right = ToDoubleRegister(instr->right());
DoubleRegister result = ToDoubleRegister(instr->result());
@@ -1627,6 +1762,7 @@
Register reg = ToRegister(instr->value());
EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg));
} else if (r.IsDouble()) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister reg = ToDoubleRegister(instr->value());
// Test the double value. Zero and NaN are false.
EmitBranchF(true_block, false_block, ne, reg, kDoubleRegZero);
@@ -1704,6 +1840,7 @@
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
+ CpuFeatures::Scope scope(FPU);
// heap number -> false iff +0, -0, or NaN.
DoubleRegister dbl_scratch = double_scratch0();
Label not_heap_number;
@@ -1783,6 +1920,7 @@
EmitGoto(next_block);
} else {
if (instr->is_double()) {
+ CpuFeatures::Scope scope(FPU);
// Compare left and right as doubles and load the
// resulting flags into the normal status register.
FPURegister left_reg = ToDoubleRegister(left);
@@ -2088,7 +2226,7 @@
__ JumpIfSmi(input, is_false);
- if (class_name->IsEqualTo(CStrVector("Function"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
// Assuming the following assertions, we can use the same compares to test
// for both being a function type and being in the object type range.
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
@@ -2117,7 +2255,7 @@
// Objects with a non-function constructor have class 'Object'.
__ GetObjectType(temp, temp2, temp2);
- if (class_name->IsEqualTo(CStrVector("Object"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
__ Branch(is_true, ne, temp2, Operand(JS_FUNCTION_TYPE));
} else {
__ Branch(is_false, ne, temp2, Operand(JS_FUNCTION_TYPE));
@@ -2330,16 +2468,18 @@
void LCodeGen::DoReturn(LReturn* instr) {
- if (FLAG_trace) {
+ if (FLAG_trace && info()->IsOptimizing()) {
// Push the return value on the stack as the parameter.
// Runtime::TraceExit returns its parameter in v0.
__ push(v0);
__ CallRuntime(Runtime::kTraceExit, 1);
}
- int32_t sp_delta = (GetParameterCount() + 1) * kPointerSize;
- __ mov(sp, fp);
- __ Pop(ra, fp);
- __ Addu(sp, sp, Operand(sp_delta));
+ if (NeedsEagerFrame()) {
+ int32_t sp_delta = (GetParameterCount() + 1) * kPointerSize;
+ __ mov(sp, fp);
+ __ Pop(ra, fp);
+ __ Addu(sp, sp, Operand(sp_delta));
+ }
__ Jump(ra);
}
@@ -2698,12 +2838,61 @@
__ sll(scratch0(), key, shift_size);
__ Addu(scratch0(), scratch0(), external_pointer);
}
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+ __ lwc1(result, MemOperand(scratch0(), additional_offset));
+ __ cvt_d_s(result, result);
+ } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
+ __ ldc1(result, MemOperand(scratch0(), additional_offset));
+ }
+ } else {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+ Register value = external_pointer;
+ __ lw(value, MemOperand(scratch0(), additional_offset));
+ __ And(sfpd_lo, value, Operand(kBinary32MantissaMask));
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- __ lwc1(result, MemOperand(scratch0(), additional_offset));
- __ cvt_d_s(result, result);
- } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
- __ ldc1(result, MemOperand(scratch0(), additional_offset));
+ __ srl(scratch0(), value, kBinary32MantissaBits);
+ __ And(scratch0(), scratch0(),
+ Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
+
+ Label exponent_rebiased;
+ __ Xor(at, scratch0(), Operand(0x00));
+ __ Branch(&exponent_rebiased, eq, at, Operand(zero_reg));
+
+ __ Xor(at, scratch0(), Operand(0xff));
+ Label skip;
+ __ Branch(&skip, ne, at, Operand(zero_reg));
+ __ li(scratch0(), Operand(0x7ff));
+ __ bind(&skip);
+ __ Branch(&exponent_rebiased, eq, at, Operand(zero_reg));
+
+ // Rebias exponent.
+ __ Addu(scratch0(),
+ scratch0(),
+ Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
+
+ __ bind(&exponent_rebiased);
+ __ And(sfpd_hi, value, Operand(kBinary32SignMask));
+ __ sll(at, scratch0(), HeapNumber::kMantissaBitsInTopWord);
+ __ Or(sfpd_hi, sfpd_hi, at);
+
+ // Shift mantissa.
+ static const int kMantissaShiftForHiWord =
+ kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
+
+ static const int kMantissaShiftForLoWord =
+ kBitsPerInt - kMantissaShiftForHiWord;
+
+ __ srl(at, sfpd_lo, kMantissaShiftForHiWord);
+ __ Or(sfpd_hi, sfpd_hi, at);
+ __ sll(sfpd_lo, sfpd_lo, kMantissaShiftForLoWord);
+
+ } else {
+ __ lw(sfpd_lo, MemOperand(scratch0(), additional_offset));
+ __ lw(sfpd_hi, MemOperand(scratch0(),
+ additional_offset + kPointerSize));
+ }
}
} else {
Register result = ToRegister(instr->result());
@@ -2772,25 +2961,28 @@
key = ToRegister(instr->key());
}
- if (key_is_constant) {
- __ Addu(elements, elements,
- Operand(((constant_key + instr->additional_index()) <<
- element_size_shift) +
- FixedDoubleArray::kHeaderSize - kHeapObjectTag));
- } else {
+ int base_offset = (FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
+ ((constant_key + instr->additional_index()) << element_size_shift);
+ if (!key_is_constant) {
__ sll(scratch, key, shift_size);
- __ Addu(elements, elements, Operand(scratch));
- __ Addu(elements, elements,
- Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
- (instr->additional_index() << element_size_shift)));
+ __ Addu(elements, elements, scratch);
}
-
- if (instr->hydrogen()->RequiresHoleCheck()) {
- __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
- DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ __ Addu(elements, elements, Operand(base_offset));
+ __ ldc1(result, MemOperand(elements));
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
+ DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
+ }
+ } else {
+ __ lw(sfpd_hi, MemOperand(elements, base_offset + kPointerSize));
+ __ lw(sfpd_lo, MemOperand(elements, base_offset));
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ ASSERT(kPointerSize == sizeof(kHoleNanLower32));
+ DeoptimizeIf(eq, instr->environment(), sfpd_hi, Operand(kHoleNanUpper32));
+ }
}
-
- __ ldc1(result, MemOperand(elements));
}
@@ -3233,6 +3425,7 @@
void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
+ CpuFeatures::Scope scope(FPU);
// Class for deferred case.
class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
public:
@@ -3269,6 +3462,7 @@
void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
Register scratch1 = scratch0();
@@ -3297,6 +3491,7 @@
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
@@ -3373,6 +3568,7 @@
void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
__ sqrt_d(result, input);
@@ -3380,6 +3576,7 @@
void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister temp = ToDoubleRegister(instr->temp());
@@ -3404,6 +3601,7 @@
void LCodeGen::DoPower(LPower* instr) {
+ CpuFeatures::Scope scope(FPU);
Representation exponent_type = instr->hydrogen()->right()->representation();
// Having marked this as a call, we can use any registers.
// Just make sure that the input/output registers are the expected ones.
@@ -3434,6 +3632,7 @@
void LCodeGen::DoRandom(LRandom* instr) {
+ CpuFeatures::Scope scope(FPU);
class DeferredDoRandom: public LDeferredCode {
public:
DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
@@ -3510,6 +3709,7 @@
void LCodeGen::DoMathExp(LMathExp* instr) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
@@ -3805,6 +4005,7 @@
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
+ CpuFeatures::Scope scope(FPU);
Register external_pointer = ToRegister(instr->elements());
Register key = no_reg;
ElementsKind elements_kind = instr->elements_kind();
@@ -3878,6 +4079,7 @@
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister value = ToDoubleRegister(instr->value());
Register elements = ToRegister(instr->elements());
Register key = no_reg;
@@ -4125,7 +4327,7 @@
ASSERT(!char_code.is(result));
__ Branch(deferred->entry(), hi,
- char_code, Operand(String::kMaxAsciiCharCode));
+ char_code, Operand(String::kMaxOneByteCharCode));
__ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
__ sll(scratch, char_code, kPointerSizeLog2);
__ Addu(result, result, scratch);
@@ -4161,6 +4363,7 @@
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
+ CpuFeatures::Scope scope(FPU);
LOperand* input = instr->value();
ASSERT(input->IsRegister() || input->IsStackSlot());
LOperand* output = instr->result();
@@ -4178,6 +4381,7 @@
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
+ CpuFeatures::Scope scope(FPU);
LOperand* input = instr->value();
LOperand* output = instr->result();
@@ -4239,13 +4443,51 @@
}
+// Convert unsigned integer with specified number of leading zeroes in binary
+// representation to IEEE 754 double.
+// Integer to convert is passed in register hiword.
+// Resulting double is returned in registers hiword:loword.
+// This functions does not work correctly for 0.
+static void GenerateUInt2Double(MacroAssembler* masm,
+ Register hiword,
+ Register loword,
+ Register scratch,
+ int leading_zeroes) {
+ const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
+ const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
+
+ const int mantissa_shift_for_hi_word =
+ meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
+ const int mantissa_shift_for_lo_word =
+ kBitsPerInt - mantissa_shift_for_hi_word;
+ masm->li(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
+ if (mantissa_shift_for_hi_word > 0) {
+ masm->sll(loword, hiword, mantissa_shift_for_lo_word);
+ masm->srl(hiword, hiword, mantissa_shift_for_hi_word);
+ masm->Or(hiword, scratch, hiword);
+ } else {
+ masm->mov(loword, zero_reg);
+ masm->sll(hiword, hiword, mantissa_shift_for_hi_word);
+ masm->Or(hiword, scratch, hiword);
+ }
+
+ // If least significant bit of biased exponent was not 1 it was corrupted
+ // by most significant bit of mantissa so we should fix that.
+ if (!(biased_exponent & 1)) {
+ masm->li(scratch, 1 << HeapNumber::kExponentShift);
+ masm->nor(scratch, scratch, scratch);
+ masm->and_(hiword, hiword, scratch);
+ }
+}
+
+
void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
LOperand* value,
IntegerSignedness signedness) {
Label slow;
Register src = ToRegister(value);
Register dst = ToRegister(instr->result());
- FPURegister dbl_scratch = double_scratch0();
+ DoubleRegister dbl_scratch = double_scratch0();
// Preserve the value of all registers.
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
@@ -4259,16 +4501,40 @@
__ SmiUntag(src, dst);
__ Xor(src, src, Operand(0x80000000));
}
- __ mtc1(src, dbl_scratch);
- __ cvt_d_w(dbl_scratch, dbl_scratch);
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ __ mtc1(src, dbl_scratch);
+ __ cvt_d_w(dbl_scratch, dbl_scratch);
+ } else {
+ FloatingPointHelper::Destination dest =
+ FloatingPointHelper::kCoreRegisters;
+ FloatingPointHelper::ConvertIntToDouble(masm(), src, dest, f0,
+ sfpd_lo, sfpd_hi,
+ scratch0(), f2);
+ }
} else {
- __ mtc1(src, dbl_scratch);
- __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ __ mtc1(src, dbl_scratch);
+ __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
+ } else {
+ Label no_leading_zero, done;
+ __ And(at, src, Operand(0x80000000));
+ __ Branch(&no_leading_zero, ne, at, Operand(zero_reg));
+
+ // Integer has one leading zeros.
+ GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, t0, 1);
+ __ Branch(&done);
+
+ __ bind(&no_leading_zero);
+ GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, t0, 0);
+ __ Branch(&done);
+ }
}
if (FLAG_inline_new) {
- __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(t1, a3, t0, t2, &slow, DONT_TAG_RESULT);
+ __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex);
+ __ AllocateHeapNumber(t1, a3, t0, scratch0(), &slow, DONT_TAG_RESULT);
__ Move(dst, t1);
__ Branch(&done);
}
@@ -4287,7 +4553,13 @@
// Done. Put the value in dbl_scratch into the value of the allocated heap
// number.
__ bind(&done);
- __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
+ } else {
+ __ sw(sfpd_lo, MemOperand(dst, HeapNumber::kMantissaOffset));
+ __ sw(sfpd_hi, MemOperand(dst, HeapNumber::kExponentOffset));
+ }
__ Addu(dst, dst, kHeapObjectTag);
__ StoreToSafepointRegisterSlot(dst, dst);
}
@@ -4320,7 +4592,13 @@
__ Branch(deferred->entry());
}
__ bind(deferred->exit());
- __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
+ } else {
+ __ sw(sfpd_lo, MemOperand(reg, HeapNumber::kValueOffset));
+ __ sw(sfpd_hi, MemOperand(reg, HeapNumber::kValueOffset + kPointerSize));
+ }
// Now that we have finished with the object's real address tag it
__ Addu(reg, reg, kHeapObjectTag);
}
@@ -4368,6 +4646,7 @@
bool deoptimize_on_minus_zero,
LEnvironment* env) {
Register scratch = scratch0();
+ CpuFeatures::Scope scope(FPU);
Label load_smi, heap_number, done;
@@ -4432,6 +4711,7 @@
// of the if.
if (instr->truncating()) {
+ CpuFeatures::Scope scope(FPU);
Register scratch3 = ToRegister(instr->temp2());
FPURegister single_scratch = double_scratch.low();
ASSERT(!scratch3.is(input_reg) &&
@@ -4637,37 +4917,38 @@
}
-void LCodeGen::DoCheckMapCommon(Register reg,
- Register scratch,
+void LCodeGen::DoCheckMapCommon(Register map_reg,
Handle<Map> map,
CompareMapMode mode,
LEnvironment* env) {
Label success;
- __ CompareMapAndBranch(reg, scratch, map, &success, eq, &success, mode);
+ __ CompareMapAndBranch(map_reg, map, &success, eq, &success, mode);
DeoptimizeIf(al, env);
__ bind(&success);
}
void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
- Register scratch = scratch0();
+ Register map_reg = scratch0();
LOperand* input = instr->value();
ASSERT(input->IsRegister());
Register reg = ToRegister(input);
Label success;
SmallMapList* map_set = instr->hydrogen()->map_set();
+ __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
for (int i = 0; i < map_set->length() - 1; i++) {
Handle<Map> map = map_set->at(i);
__ CompareMapAndBranch(
- reg, scratch, map, &success, eq, &success, REQUIRE_EXACT_MAP);
+ map_reg, map, &success, eq, &success, REQUIRE_EXACT_MAP);
}
Handle<Map> map = map_set->last();
- DoCheckMapCommon(reg, scratch, map, REQUIRE_EXACT_MAP, instr->environment());
+ DoCheckMapCommon(map_reg, map, REQUIRE_EXACT_MAP, instr->environment());
__ bind(&success);
}
void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
+ CpuFeatures::Scope vfp_scope(FPU);
DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
@@ -4676,6 +4957,7 @@
void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
+ CpuFeatures::Scope vfp_scope(FPU);
Register unclamped_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
__ ClampUint8(result_reg, unclamped_reg);
@@ -4683,6 +4965,7 @@
void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
+ CpuFeatures::Scope vfp_scope(FPU);
Register scratch = scratch0();
Register input_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
@@ -4719,28 +5002,30 @@
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
ASSERT(instr->temp()->Equals(instr->result()));
- Register temp1 = ToRegister(instr->temp());
- Register temp2 = ToRegister(instr->temp2());
+ Register prototype_reg = ToRegister(instr->temp());
+ Register map_reg = ToRegister(instr->temp2());
Handle<JSObject> holder = instr->holder();
Handle<JSObject> current_prototype = instr->prototype();
// Load prototype object.
- __ LoadHeapObject(temp1, current_prototype);
+ __ LoadHeapObject(prototype_reg, current_prototype);
// Check prototype maps up to the holder.
while (!current_prototype.is_identical_to(holder)) {
- DoCheckMapCommon(temp1, temp2,
+ __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
+ DoCheckMapCommon(map_reg,
Handle<Map>(current_prototype->map()),
ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
current_prototype =
Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
// Load next prototype object.
- __ LoadHeapObject(temp1, current_prototype);
+ __ LoadHeapObject(prototype_reg, current_prototype);
}
// Check the holder map.
- DoCheckMapCommon(temp1, temp2,
+ __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
+ DoCheckMapCommon(map_reg,
Handle<Map>(current_prototype->map()),
ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
}
@@ -5304,6 +5589,7 @@
void LCodeGen::EnsureSpaceForLazyDeopt() {
+ if (info()->IsStub()) return;
// Ensure that we have enough space after the previous lazy-bailout
// instruction for patching the code here.
int current_pc = masm()->pc_offset();
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index 7363eb8..443a20a 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -61,6 +61,7 @@
deferred_(8, info->zone()),
osr_pc_offset_(-1),
last_lazy_deopt_pc_(0),
+ frame_is_built_(false),
safepoints_(info->zone()),
resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) {
@@ -76,6 +77,15 @@
Heap* heap() const { return isolate()->heap(); }
Zone* zone() const { return zone_; }
+ bool NeedsEagerFrame() const {
+ return GetStackSlotCount() > 0 ||
+ info()->is_non_deferred_calling() ||
+ !info()->IsStub();
+ }
+ bool NeedsDeferredFrame() const {
+ return !NeedsEagerFrame() && info()->is_deferred_calling();
+ }
+
// Support for converting LOperands to assembler types.
// LOperand must be a register.
Register ToRegister(LOperand* op) const;
@@ -126,7 +136,7 @@
void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
- void DoCheckMapCommon(Register reg, Register scratch, Handle<Map> map,
+ void DoCheckMapCommon(Register map_reg, Handle<Map> map,
CompareMapMode mode, LEnvironment* env);
// Parallel move support.
@@ -189,7 +199,7 @@
Register temporary2);
int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
- int GetParameterCount() const { return scope()->num_parameters(); }
+ int GetParameterCount() const { return info()->num_parameters(); }
void Abort(const char* reason);
void Comment(const char* format, ...);
@@ -368,11 +378,15 @@
int* offset);
struct JumpTableEntry {
- explicit inline JumpTableEntry(Address entry)
+ inline JumpTableEntry(Address entry, bool frame, bool is_lazy)
: label(),
- address(entry) { }
+ address(entry),
+ needs_frame(frame),
+ is_lazy_deopt(is_lazy) { }
Label label;
Address address;
+ bool needs_frame;
+ bool is_lazy_deopt;
};
void EnsureSpaceForLazyDeopt();
@@ -401,6 +415,7 @@
ZoneList<LDeferredCode*> deferred_;
int osr_pc_offset_;
int last_lazy_deopt_pc_;
+ bool frame_is_built_;
// Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code.
@@ -416,6 +431,7 @@
PushSafepointRegistersScope(LCodeGen* codegen,
Safepoint::Kind kind)
: codegen_(codegen) {
+ ASSERT(codegen_->info()->is_calling());
ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
codegen_->expected_safepoint_kind_ = kind;
diff --git a/src/mips/lithium-gap-resolver-mips.cc b/src/mips/lithium-gap-resolver-mips.cc
index 87efae5..a4a4411 100644
--- a/src/mips/lithium-gap-resolver-mips.cc
+++ b/src/mips/lithium-gap-resolver-mips.cc
@@ -172,8 +172,10 @@
} else if (source->IsStackSlot()) {
__ lw(kLithiumScratchReg, cgen_->ToMemOperand(source));
} else if (source->IsDoubleRegister()) {
+ CpuFeatures::Scope scope(FPU);
__ mov_d(kLithiumScratchDouble, cgen_->ToDoubleRegister(source));
} else if (source->IsDoubleStackSlot()) {
+ CpuFeatures::Scope scope(FPU);
__ ldc1(kLithiumScratchDouble, cgen_->ToMemOperand(source));
} else {
UNREACHABLE();
@@ -193,9 +195,11 @@
} else if (saved_destination_->IsStackSlot()) {
__ sw(kLithiumScratchReg, cgen_->ToMemOperand(saved_destination_));
} else if (saved_destination_->IsDoubleRegister()) {
+ CpuFeatures::Scope scope(FPU);
__ mov_d(cgen_->ToDoubleRegister(saved_destination_),
kLithiumScratchDouble);
} else if (saved_destination_->IsDoubleStackSlot()) {
+ CpuFeatures::Scope scope(FPU);
__ sdc1(kLithiumScratchDouble,
cgen_->ToMemOperand(saved_destination_));
} else {
@@ -232,6 +236,7 @@
MemOperand destination_operand = cgen_->ToMemOperand(destination);
if (in_cycle_) {
if (!destination_operand.OffsetIsInt16Encodable()) {
+ CpuFeatures::Scope scope(FPU);
// 'at' is overwritten while saving the value to the destination.
// Therefore we can't use 'at'. It is OK if the read from the source
// destroys 'at', since that happens before the value is read.
@@ -271,6 +276,7 @@
}
} else if (source->IsDoubleRegister()) {
+ CpuFeatures::Scope scope(FPU);
DoubleRegister source_register = cgen_->ToDoubleRegister(source);
if (destination->IsDoubleRegister()) {
__ mov_d(cgen_->ToDoubleRegister(destination), source_register);
@@ -281,6 +287,7 @@
}
} else if (source->IsDoubleStackSlot()) {
+ CpuFeatures::Scope scope(FPU);
MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsDoubleRegister()) {
__ ldc1(cgen_->ToDoubleRegister(destination), source_operand);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 0e58eb5..8ce576d 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -42,10 +42,10 @@
#undef DEFINE_COMPILE
LOsrEntry::LOsrEntry() {
- for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
+ for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) {
register_spills_[i] = NULL;
}
- for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
+ for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
double_register_spills_[i] = NULL;
}
}
@@ -616,6 +616,7 @@
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize) {
+ info()->MarkAsNonDeferredCalling();
#ifdef DEBUG
instr->VerifyCall();
#endif
@@ -1001,7 +1002,14 @@
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
- return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
+ // If there is a non-return use, the context must be allocated in a register.
+ for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+ if (!it.value()->IsReturn()) {
+ return DefineAsRegister(new(zone()) LContext);
+ }
+ }
+
+ return NULL;
}
@@ -1275,8 +1283,22 @@
return DefineAsRegister(mul);
} else if (instr->representation().IsDouble()) {
+ if (kArchVariant == kMips32r2) {
+ if (instr->UseCount() == 1 && instr->uses().value()->IsAdd()) {
+ HAdd* add = HAdd::cast(instr->uses().value());
+ if (instr == add->left()) {
+ // This mul is the lhs of an add. The add and mul will be folded
+ // into a multiply-add.
+ return NULL;
+ }
+ if (instr == add->right() && !add->left()->IsMul()) {
+ // This mul is the rhs of an add, where the lhs is not another mul.
+ // The add and mul will be folded into a multiply-add.
+ return NULL;
+ }
+ }
+ }
return DoArithmeticD(Token::MUL, instr);
-
} else {
return DoArithmeticT(Token::MUL, instr);
}
@@ -1303,6 +1325,15 @@
}
+LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
+ LOperand* multiplier_op = UseRegisterAtStart(mul->left());
+ LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
+ LOperand* addend_op = UseRegisterAtStart(addend);
+ return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op, multiplier_op,
+ multiplicand_op));
+}
+
+
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
@@ -1316,6 +1347,15 @@
}
return result;
} else if (instr->representation().IsDouble()) {
+ if (kArchVariant == kMips32r2) {
+ if (instr->left()->IsMul())
+ return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
+
+ if (instr->right()->IsMul()) {
+ ASSERT(!instr->left()->IsMul());
+ return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
+ }
+ }
return DoArithmeticD(Token::ADD, instr);
} else {
ASSERT(instr->representation().IsTagged());
@@ -1583,6 +1623,7 @@
Representation to = instr->to();
if (from.IsTagged()) {
if (to.IsDouble()) {
+ info()->MarkAsDeferredCalling();
LOperand* value = UseRegister(instr->value());
LNumberUntagD* res = new(zone()) LNumberUntagD(value);
return AssignEnvironment(DefineAsRegister(res));
@@ -1607,6 +1648,7 @@
}
} else if (from.IsDouble()) {
if (to.IsTagged()) {
+ info()->MarkAsDeferredCalling();
LOperand* value = UseRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
@@ -1626,6 +1668,7 @@
return AssignEnvironment(DefineAsRegister(res));
}
} else if (from.IsInteger32()) {
+ info()->MarkAsDeferredCalling();
if (to.IsTagged()) {
HValue* val = instr->value();
LOperand* value = UseRegisterAtStart(val);
@@ -1864,7 +1907,16 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
- LOperand* external_pointer = UseRegister(instr->elements());
+ // float->double conversion on non-VFP2 requires an extra scratch
+ // register. For convenience, just mark the elements register as "UseTemp"
+ // so that it can be used as a temp during the float->double conversion
+ // after it's no longer needed after the float load.
+ bool needs_temp =
+ !CpuFeatures::IsSupported(FPU) &&
+ (elements_kind == EXTERNAL_FLOAT_ELEMENTS);
+ LOperand* external_pointer = needs_temp
+ ? UseTempRegister(instr->elements())
+ : UseRegister(instr->elements());
result = new(zone()) LLoadKeyed(external_pointer, key);
}
@@ -2083,8 +2135,17 @@
LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
- int spill_index = chunk()->GetParameterStackSlot(instr->index());
- return DefineAsSpilled(new(zone()) LParameter, spill_index);
+ LParameter* result = new(zone()) LParameter;
+ if (info()->IsOptimizing()) {
+ int spill_index = chunk()->GetParameterStackSlot(instr->index());
+ return DefineAsSpilled(result, spill_index);
+ } else {
+ ASSERT(info()->IsStub());
+ CodeStubInterfaceDescriptor* descriptor =
+ info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
+ Register reg = descriptor->register_params_[instr->index()];
+ return DefineFixed(result, reg);
+ }
}
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index b2ed72a..7f87b02 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -135,6 +135,7 @@
V(MathMinMax) \
V(ModI) \
V(MulI) \
+ V(MultiplyAddD) \
V(NumberTagD) \
V(NumberTagI) \
V(NumberTagU) \
@@ -252,6 +253,11 @@
void MarkAsCall() { is_call_ = true; }
// Interface to the register allocator and iterators.
+ bool ClobbersTemps() const { return is_call_; }
+ bool ClobbersRegisters() const { return is_call_; }
+ bool ClobbersDoubleRegisters() const { return is_call_; }
+
+ // Interface to the register allocator and iterators.
bool IsMarkedAsCall() const { return is_call_; }
virtual bool HasResult() const = 0;
@@ -603,6 +609,24 @@
};
+// Instruction for computing multiplier * multiplicand + addend.
+class LMultiplyAddD: public LTemplateInstruction<1, 3, 0> {
+ public:
+ LMultiplyAddD(LOperand* addend, LOperand* multiplier,
+ LOperand* multiplicand) {
+ inputs_[0] = addend;
+ inputs_[1] = multiplier;
+ inputs_[2] = multiplicand;
+ }
+
+ LOperand* addend() { return inputs_[0]; }
+ LOperand* multiplier() { return inputs_[1]; }
+ LOperand* multiplicand() { return inputs_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MultiplyAddD, "multiply-add-d")
+};
+
+
class LCmpIDAndBranch: public LControlInstruction<2, 0> {
public:
LCmpIDAndBranch(LOperand* left, LOperand* right) {
@@ -2304,8 +2328,9 @@
// slot, i.e., that must also be restored to the spill slot on OSR entry.
// NULL if the register has no assigned spill slot. Indexed by allocation
// index.
- LOperand* register_spills_[Register::kNumAllocatableRegisters];
- LOperand* double_register_spills_[DoubleRegister::kNumAllocatableRegisters];
+ LOperand* register_spills_[Register::kMaxNumAllocatableRegisters];
+ LOperand* double_register_spills_[
+ DoubleRegister::kMaxNumAllocatableRegisters];
};
@@ -2427,6 +2452,8 @@
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
+ LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
+
private:
enum Status {
UNUSED,
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 9249917..e0c5787 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -118,8 +118,8 @@
void MacroAssembler::PushSafepointRegistersAndDoubles() {
PushSafepointRegisters();
- Subu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize));
- for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) {
+ Subu(sp, sp, Operand(FPURegister::NumAllocatableRegisters() * kDoubleSize));
+ for (int i = 0; i < FPURegister::NumAllocatableRegisters(); i+=2) {
FPURegister reg = FPURegister::FromAllocationIndex(i);
sdc1(reg, MemOperand(sp, i * kDoubleSize));
}
@@ -127,11 +127,11 @@
void MacroAssembler::PopSafepointRegistersAndDoubles() {
- for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) {
+ for (int i = 0; i < FPURegister::NumAllocatableRegisters(); i+=2) {
FPURegister reg = FPURegister::FromAllocationIndex(i);
ldc1(reg, MemOperand(sp, i * kDoubleSize));
}
- Addu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize));
+ Addu(sp, sp, Operand(FPURegister::NumAllocatableRegisters() * kDoubleSize));
PopSafepointRegisters();
}
@@ -167,7 +167,7 @@
MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
UNIMPLEMENTED_MIPS();
// General purpose registers are pushed last on the stack.
- int doubles_size = FPURegister::kNumAllocatableRegisters * kDoubleSize;
+ int doubles_size = FPURegister::NumAllocatableRegisters() * kDoubleSize;
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
return MemOperand(sp, doubles_size + register_offset);
}
@@ -3935,12 +3935,13 @@
// Runtime calls.
void MacroAssembler::CallStub(CodeStub* stub,
+ TypeFeedbackId ast_id,
Condition cond,
Register r1,
const Operand& r2,
BranchDelaySlot bd) {
ASSERT(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
- Call(stub->GetCode(), RelocInfo::CODE_TARGET, TypeFeedbackId::None(),
+ Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id,
cond, r1, r2, bd);
}
@@ -4249,7 +4250,10 @@
const Runtime::Function* function = Runtime::FunctionForId(id);
PrepareCEntryArgs(function->nargs);
PrepareCEntryFunction(ExternalReference(function, isolate()));
- CEntryStub stub(1, kSaveFPRegs);
+ SaveFPRegsMode mode = CpuFeatures::IsSupported(FPU)
+ ? kSaveFPRegs
+ : kDontSaveFPRegs;
+ CEntryStub stub(1, mode);
CallStub(&stub);
}
@@ -4266,7 +4270,7 @@
PrepareCEntryFunction(ext);
CEntryStub stub(1);
- CallStub(&stub, al, zero_reg, Operand(zero_reg), bd);
+ CallStub(&stub, TypeFeedbackId::None(), al, zero_reg, Operand(zero_reg), bd);
}
@@ -5445,6 +5449,27 @@
}
+void MacroAssembler::TestJSArrayForAllocationSiteInfo(
+ Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present) {
+ Label no_info_available;
+ ExternalReference new_space_start =
+ ExternalReference::new_space_start(isolate());
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+ lw(scratch_reg, FieldMemOperand(receiver_reg,
+ JSArray::kSize + AllocationSiteInfo::kSize));
+ Branch(&no_info_available, lt, scratch_reg, Operand(new_space_start));
+ Branch(&no_info_available, hs, scratch_reg,
+ Operand(new_space_allocation_top));
+ lw(scratch_reg, MemOperand(scratch_reg));
+ Branch(allocation_info_present, eq, scratch_reg,
+ Operand(Handle<Map>(isolate()->heap()->allocation_site_info_map())));
+ bind(&no_info_available);
+}
+
+
bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
if (r1.is(r2)) return true;
if (r1.is(r3)) return true;
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 474772e..1a37aca 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -1141,6 +1141,7 @@
// Call a code stub.
void CallStub(CodeStub* stub,
+ TypeFeedbackId ast_id = TypeFeedbackId::None(),
Condition cond = cc_always,
Register r1 = zero_reg,
const Operand& r2 = Operand(zero_reg),
@@ -1439,6 +1440,16 @@
// in a0. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Register null_value, Label* call_runtime);
+ // AllocationSiteInfo support. Arrays may have an associated
+ // AllocationSiteInfo object that can be checked for in order to pretransition
+ // to another type.
+ // On entry, receiver_reg should point to the array object.
+ // scratch_reg gets clobbered.
+ // If allocation info is present, jump to allocation_info_present
+ void TestJSArrayForAllocationSiteInfo(Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present);
+
private:
void CallCFunctionHelper(Register function,
int num_reg_arguments,
@@ -1513,9 +1524,9 @@
// This handle will be patched with the code object on installation.
Handle<Object> code_object_;
- // Needs access to SafepointRegisterStackIndex for optimized frame
+ // Needs access to SafepointRegisterStackIndex for compiled frame
// traversal.
- friend class OptimizedFrame;
+ friend class StandardFrame;
};
diff --git a/src/mips/regexp-macro-assembler-mips.cc b/src/mips/regexp-macro-assembler-mips.cc
index 0dd72de..6ace471 100644
--- a/src/mips/regexp-macro-assembler-mips.cc
+++ b/src/mips/regexp-macro-assembler-mips.cc
@@ -262,7 +262,7 @@
if (mode_ == ASCII) {
__ lbu(a1, MemOperand(a0, 0));
__ addiu(a0, a0, char_size());
- ASSERT(str[i] <= String::kMaxAsciiCharCode);
+ ASSERT(str[i] <= String::kMaxOneByteCharCode);
BranchOrBacktrack(on_failure, ne, a1, Operand(str[i]));
} else {
__ lhu(a1, MemOperand(a0, 0));
@@ -511,7 +511,7 @@
Handle<ByteArray> table,
Label* on_bit_set) {
__ li(a0, Operand(table));
- if (mode_ != ASCII || kTableMask != String::kMaxAsciiCharCode) {
+ if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) {
__ And(a1, current_character(), Operand(kTableSize - 1));
__ Addu(a0, a0, a1);
} else {
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index ea359ea..be9f369 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -1545,7 +1545,7 @@
FUNCTION_ADDR(target), arg1);
}
v8::Handle<v8::Value> result = target(arg1);
- *(reinterpret_cast<int*>(arg0)) = (int32_t) *result;
+ *(reinterpret_cast<int*>(arg0)) = reinterpret_cast<int32_t>(*result);
set_register(v0, arg0);
} else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
// See DirectCEntryStub::GenerateCall for explanation of register usage.
@@ -1556,7 +1556,7 @@
FUNCTION_ADDR(target), arg1, arg2);
}
v8::Handle<v8::Value> result = target(arg1, arg2);
- *(reinterpret_cast<int*>(arg0)) = (int32_t) *result;
+ *(reinterpret_cast<int*>(arg0)) = reinterpret_cast<int32_t>(*result);
set_register(v0, arg0);
} else {
SimulatorRuntimeCall target =
@@ -1760,6 +1760,8 @@
UNIMPLEMENTED_MIPS();
};
break;
+ case COP1X:
+ break;
case SPECIAL:
switch (instr->FunctionFieldRaw()) {
case JR:
@@ -1949,6 +1951,7 @@
const uint32_t rt_u = static_cast<uint32_t>(rt);
const int32_t rd_reg = instr->RdValue();
+ const int32_t fr_reg = instr->FrValue();
const int32_t fs_reg = instr->FsValue();
const int32_t ft_reg = instr->FtValue();
const int32_t fd_reg = instr->FdValue();
@@ -2193,8 +2196,8 @@
case CVT_D_L: // Mips32r2 instruction.
// Watch the signs here, we want 2 32-bit vals
// to make a sign-64.
- i64 = (uint32_t) get_fpu_register(fs_reg);
- i64 |= ((int64_t) get_fpu_register(fs_reg + 1) << 32);
+ i64 = static_cast<uint32_t>(get_fpu_register(fs_reg));
+ i64 |= static_cast<int64_t>(get_fpu_register(fs_reg + 1)) << 32;
set_fpu_register_double(fd_reg, static_cast<double>(i64));
break;
case CVT_S_L:
@@ -2210,6 +2213,19 @@
UNREACHABLE();
};
break;
+ case COP1X:
+ switch (instr->FunctionFieldRaw()) {
+ case MADD_D:
+ double fr, ft, fs;
+ fr = get_fpu_register_double(fr_reg);
+ fs = get_fpu_register_double(fs_reg);
+ ft = get_fpu_register_double(ft_reg);
+ set_fpu_register_double(fd_reg, fs * ft + fr);
+ break;
+ default:
+ UNREACHABLE();
+ };
+ break;
case SPECIAL:
switch (instr->FunctionFieldRaw()) {
case JR: {
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 323933b..0313826 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -1054,46 +1054,6 @@
}
-// Convert unsigned integer with specified number of leading zeroes in binary
-// representation to IEEE 754 double.
-// Integer to convert is passed in register hiword.
-// Resulting double is returned in registers hiword:loword.
-// This functions does not work correctly for 0.
-static void GenerateUInt2Double(MacroAssembler* masm,
- Register hiword,
- Register loword,
- Register scratch,
- int leading_zeroes) {
- const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
- const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
-
- const int mantissa_shift_for_hi_word =
- meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
-
- const int mantissa_shift_for_lo_word =
- kBitsPerInt - mantissa_shift_for_hi_word;
-
- __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
- if (mantissa_shift_for_hi_word > 0) {
- __ sll(loword, hiword, mantissa_shift_for_lo_word);
- __ srl(hiword, hiword, mantissa_shift_for_hi_word);
- __ or_(hiword, scratch, hiword);
- } else {
- __ mov(loword, zero_reg);
- __ sll(hiword, hiword, mantissa_shift_for_hi_word);
- __ or_(hiword, scratch, hiword);
- }
-
- // If least significant bit of biased exponent was not 1 it was corrupted
- // by most significant bit of mantissa so we should fix that.
- if (!(biased_exponent & 1)) {
- __ li(scratch, 1 << HeapNumber::kExponentShift);
- __ nor(scratch, scratch, scratch);
- __ and_(hiword, hiword, scratch);
- }
-}
-
-
#undef __
#define __ ACCESS_MASM(masm())
@@ -3316,9 +3276,17 @@
// -- a1 : receiver
// -----------------------------------
ElementsKind elements_kind = receiver_map->elements_kind();
- Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
-
- __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
+ if (receiver_map->has_fast_elements() ||
+ receiver_map->has_external_array_elements()) {
+ Handle<Code> stub = KeyedLoadFastElementStub(
+ receiver_map->instance_type() == JS_ARRAY_TYPE,
+ elements_kind).GetCode();
+ __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
+ } else {
+ Handle<Code> stub =
+ KeyedLoadDictionaryElementStub().GetCode();
+ __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
+ }
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
@@ -3351,7 +3319,7 @@
__ Jump(miss_ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
+ return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
}
@@ -3454,7 +3422,7 @@
__ Jump(miss_ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
+ return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
}
@@ -3730,355 +3698,6 @@
}
-void KeyedLoadStubCompiler::GenerateLoadExternalArray(
- MacroAssembler* masm,
- ElementsKind elements_kind) {
- // ---------- S t a t e --------------
- // -- ra : return address
- // -- a0 : key
- // -- a1 : receiver
- // -----------------------------------
- Label miss_force_generic, slow, failed_allocation;
-
- Register key = a0;
- Register receiver = a1;
-
- // This stub is meant to be tail-jumped to, the receiver must already
- // have been verified by the caller to not be a smi.
-
- // Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
-
- __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
- // a3: elements array
-
- // Check that the index is in range.
- __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
- __ sra(t2, key, kSmiTagSize);
- // Unsigned comparison catches both negative and too-large values.
- __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
-
- __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
- // a3: base pointer of external storage
-
- // We are not untagging smi key and instead work with it
- // as if it was premultiplied by 2.
- STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
-
- Register value = a2;
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- __ srl(t2, key, 1);
- __ addu(t3, a3, t2);
- __ lb(value, MemOperand(t3, 0));
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ srl(t2, key, 1);
- __ addu(t3, a3, t2);
- __ lbu(value, MemOperand(t3, 0));
- break;
- case EXTERNAL_SHORT_ELEMENTS:
- __ addu(t3, a3, key);
- __ lh(value, MemOperand(t3, 0));
- break;
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ addu(t3, a3, key);
- __ lhu(value, MemOperand(t3, 0));
- break;
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ sll(t2, key, 1);
- __ addu(t3, a3, t2);
- __ lw(value, MemOperand(t3, 0));
- break;
- case EXTERNAL_FLOAT_ELEMENTS:
- __ sll(t3, t2, 2);
- __ addu(t3, a3, t3);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatures::Scope scope(FPU);
- __ lwc1(f0, MemOperand(t3, 0));
- } else {
- __ lw(value, MemOperand(t3, 0));
- }
- break;
- case EXTERNAL_DOUBLE_ELEMENTS:
- __ sll(t2, key, 2);
- __ addu(t3, a3, t2);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatures::Scope scope(FPU);
- __ ldc1(f0, MemOperand(t3, 0));
- } else {
- // t3: pointer to the beginning of the double we want to load.
- __ lw(a2, MemOperand(t3, 0));
- __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
- }
- break;
- case FAST_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
-
- // For integer array types:
- // a2: value
- // For float array type:
- // f0: value (if FPU is supported)
- // a2: value (if FPU is not supported)
- // For double array type:
- // f0: value (if FPU is supported)
- // a2/a3: value (if FPU is not supported)
-
- if (elements_kind == EXTERNAL_INT_ELEMENTS) {
- // For the Int and UnsignedInt array types, we need to see whether
- // the value can be represented in a Smi. If not, we need to convert
- // it to a HeapNumber.
- Label box_int;
- __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
- __ Branch(&box_int, lt, t3, Operand(zero_reg));
- // Tag integer as smi and return it.
- __ sll(v0, value, kSmiTagSize);
- __ Ret();
-
- __ bind(&box_int);
-
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatures::Scope scope(FPU);
- // Allocate a HeapNumber for the result and perform int-to-double
- // conversion.
- // The arm version uses a temporary here to save r0, but we don't need to
- // (a0 is not modified).
- __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, a3, t0, t1, &slow, DONT_TAG_RESULT);
- __ mtc1(value, f0);
- __ cvt_d_w(f0, f0);
- __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
- __ Addu(v0, v0, kHeapObjectTag);
- __ Ret();
- } else {
- // Allocate a HeapNumber for the result and perform int-to-double
- // conversion.
- // The arm version uses a temporary here to save r0, but we don't need to
- // (a0 is not modified).
- __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, a3, t0, t1, &slow, TAG_RESULT);
- Register dst_mantissa = t2;
- Register dst_exponent = t3;
- FloatingPointHelper::Destination dest =
- FloatingPointHelper::kCoreRegisters;
- FloatingPointHelper::ConvertIntToDouble(masm,
- value,
- dest,
- f0,
- dst_mantissa,
- dst_exponent,
- t1,
- f2);
- __ sw(dst_mantissa, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
- __ sw(dst_exponent, FieldMemOperand(v0, HeapNumber::kExponentOffset));
- __ Ret();
- }
- } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
- // The test is different for unsigned int values. Since we need
- // the value to be in the range of a positive smi, we can't
- // handle either of the top two bits being set in the value.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatures::Scope scope(FPU);
- Label pl_box_int;
- __ And(t2, value, Operand(0xC0000000));
- __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
-
- // It can fit in an Smi.
- // Tag integer as smi and return it.
- __ sll(v0, value, kSmiTagSize);
- __ Ret();
-
- __ bind(&pl_box_int);
- // Allocate a HeapNumber for the result and perform int-to-double
- // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
- // registers - also when jumping due to exhausted young space.
- __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t2, t3, t6, &slow, DONT_TAG_RESULT);
-
- // This is replaced by a macro:
- // __ mtc1(value, f0); // LS 32-bits.
- // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
- // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
-
- __ Cvt_d_uw(f0, value, f22);
-
- __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
-
- __ Addu(v0, v0, kHeapObjectTag);
- __ Ret();
- } else {
- // Check whether unsigned integer fits into smi.
- Label box_int_0, box_int_1, done;
- __ And(t2, value, Operand(0x80000000));
- __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
- __ And(t2, value, Operand(0x40000000));
- __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
-
- // Tag integer as smi and return it.
- __ sll(v0, value, kSmiTagSize);
- __ Ret();
-
- Register hiword = value; // a2.
- Register loword = a3;
-
- __ bind(&box_int_0);
- // Integer does not have leading zeros.
- GenerateUInt2Double(masm, hiword, loword, t0, 0);
- __ Branch(&done);
-
- __ bind(&box_int_1);
- // Integer has one leading zero.
- GenerateUInt2Double(masm, hiword, loword, t0, 1);
-
-
- __ bind(&done);
- // Integer was converted to double in registers hiword:loword.
- // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
- // clobbers all registers - also when jumping due to exhausted young
- // space.
- __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(t2, t3, t5, t6, &slow, TAG_RESULT);
-
- __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
- __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
-
- __ mov(v0, t2);
- __ Ret();
- }
- } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- // For the floating-point array type, we need to always allocate a
- // HeapNumber.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatures::Scope scope(FPU);
- // Allocate a HeapNumber for the result. Don't use a0 and a1 as
- // AllocateHeapNumber clobbers all registers - also when jumping due to
- // exhausted young space.
- __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT);
- // The float (single) value is already in fpu reg f0 (if we use float).
- __ cvt_d_s(f0, f0);
- __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
-
- __ Addu(v0, v0, kHeapObjectTag);
- __ Ret();
- } else {
- // Allocate a HeapNumber for the result. Don't use a0 and a1 as
- // AllocateHeapNumber clobbers all registers - also when jumping due to
- // exhausted young space.
- __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT);
- // FPU is not available, do manual single to double conversion.
-
- // a2: floating point value (binary32).
- // v0: heap number for result
-
- // Extract mantissa to t4.
- __ And(t4, value, Operand(kBinary32MantissaMask));
-
- // Extract exponent to t5.
- __ srl(t5, value, kBinary32MantissaBits);
- __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
-
- Label exponent_rebiased;
- __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
-
- __ li(t0, 0x7ff);
- __ Xor(t1, t5, Operand(0xFF));
- __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
- __ Branch(&exponent_rebiased, eq, t1, Operand(zero_reg));
-
- // Rebias exponent.
- __ Addu(t5,
- t5,
- Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
-
- __ bind(&exponent_rebiased);
- __ And(a2, value, Operand(kBinary32SignMask));
- value = no_reg;
- __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
- __ or_(a2, a2, t0);
-
- // Shift mantissa.
- static const int kMantissaShiftForHiWord =
- kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
- static const int kMantissaShiftForLoWord =
- kBitsPerInt - kMantissaShiftForHiWord;
-
- __ srl(t0, t4, kMantissaShiftForHiWord);
- __ or_(a2, a2, t0);
- __ sll(a0, t4, kMantissaShiftForLoWord);
-
- __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
- __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
- __ Ret();
- }
-
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatures::Scope scope(FPU);
- // Allocate a HeapNumber for the result. Don't use a0 and a1 as
- // AllocateHeapNumber clobbers all registers - also when jumping due to
- // exhausted young space.
- __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT);
- // The double value is already in f0
- __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
-
- __ Addu(v0, v0, kHeapObjectTag);
- __ Ret();
- } else {
- // Allocate a HeapNumber for the result. Don't use a0 and a1 as
- // AllocateHeapNumber clobbers all registers - also when jumping due to
- // exhausted young space.
- __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT);
-
- __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
- __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
- __ Ret();
- }
-
- } else {
- // Tag integer as smi and return it.
- __ sll(v0, value, kSmiTagSize);
- __ Ret();
- }
-
- // Slow case, key and receiver still in a0 and a1.
- __ bind(&slow);
- __ IncrementCounter(
- masm->isolate()->counters()->keyed_load_external_array_slow(),
- 1, a2, a3);
-
- // ---------- S t a t e --------------
- // -- ra : return address
- // -- a0 : key
- // -- a1 : receiver
- // -----------------------------------
-
- __ Push(a1, a0);
-
- __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
-
- __ bind(&miss_force_generic);
- Handle<Code> stub =
- masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
- __ Jump(stub, RelocInfo::CODE_TARGET);
-}
-
-
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
ElementsKind elements_kind) {
@@ -4478,115 +4097,6 @@
}
-void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- ra : return address
- // -- a0 : key
- // -- a1 : receiver
- // -----------------------------------
- Label miss_force_generic;
-
- // This stub is meant to be tail-jumped to, the receiver must already
- // have been verified by the caller to not be a smi.
-
- // Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, a0, t0, t1, f2, f4, &miss_force_generic);
-
- // Get the elements array.
- __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
- __ AssertFastElements(a2);
-
- // Check that the key is within bounds.
- __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
- __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
-
- // Load the result and make sure it's not the hole.
- __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
- __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(t0, t0, a3);
- __ lw(t0, MemOperand(t0));
- __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
- __ Branch(&miss_force_generic, eq, t0, Operand(t1));
- __ Ret(USE_DELAY_SLOT);
- __ mov(v0, t0);
-
- __ bind(&miss_force_generic);
- Handle<Code> stub =
- masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
- __ Jump(stub, RelocInfo::CODE_TARGET);
-}
-
-
-void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
- MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- ra : return address
- // -- a0 : key
- // -- a1 : receiver
- // -----------------------------------
- Label miss_force_generic, slow_allocate_heapnumber;
-
- Register key_reg = a0;
- Register receiver_reg = a1;
- Register elements_reg = a2;
- Register heap_number_reg = a2;
- Register indexed_double_offset = a3;
- Register scratch = t0;
- Register scratch2 = t1;
- Register scratch3 = t2;
- Register heap_number_map = t3;
-
- // This stub is meant to be tail-jumped to, the receiver must already
- // have been verified by the caller to not be a smi.
-
- // Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
-
- // Get the elements array.
- __ lw(elements_reg,
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
-
- // Check that the key is within bounds.
- __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
- __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
-
- // Load the upper word of the double in the fixed array and test for NaN.
- __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
- __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
- uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
- __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
- __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
-
- // Non-NaN. Allocate a new heap number and copy the double value into it.
- __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
- heap_number_map, &slow_allocate_heapnumber, TAG_RESULT);
-
- // Don't need to reload the upper 32 bits of the double, it's already in
- // scratch.
- __ sw(scratch, FieldMemOperand(heap_number_reg,
- HeapNumber::kExponentOffset));
- __ lw(scratch, FieldMemOperand(indexed_double_offset,
- FixedArray::kHeaderSize));
- __ sw(scratch, FieldMemOperand(heap_number_reg,
- HeapNumber::kMantissaOffset));
-
- __ mov(v0, heap_number_reg);
- __ Ret();
-
- __ bind(&slow_allocate_heapnumber);
- Handle<Code> slow_ic =
- masm->isolate()->builtins()->KeyedLoadIC_Slow();
- __ Jump(slow_ic, RelocInfo::CODE_TARGET);
-
- __ bind(&miss_force_generic);
- Handle<Code> miss_ic =
- masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
- __ Jump(miss_ic, RelocInfo::CODE_TARGET);
-}
-
-
void KeyedStoreStubCompiler::GenerateStoreFastElement(
MacroAssembler* masm,
bool is_js_array,
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 5045e1e..e99c45b 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -473,7 +473,9 @@
void SeqOneByteString::SeqOneByteStringVerify() {
- CHECK(String::IsAscii(GetChars(), length()));
+#ifndef ENABLE_LATIN_1
+ CHECK(!HasOnlyAsciiChars() || String::IsAscii(GetChars(), length()));
+#endif
}
@@ -774,6 +776,13 @@
}
+void AllocationSiteInfo::AllocationSiteInfoVerify() {
+ CHECK(IsAllocationSiteInfo());
+ VerifyHeapPointer(payload());
+ CHECK(payload()->IsObject());
+}
+
+
void Script::ScriptVerify() {
CHECK(IsScript());
VerifyPointer(source());
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 89623bd..658214a 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -345,6 +345,11 @@
}
+bool String::IsOneByteConvertible() {
+ return HasOnlyAsciiChars() || IsOneByteRepresentation();
+}
+
+
bool StringShape::IsCons() {
return (type_ & kStringRepresentationMask) == kConsStringTag;
}
@@ -1038,8 +1043,8 @@
}
-Failure* Failure::OutOfMemoryException() {
- return Construct(OUT_OF_MEMORY_EXCEPTION);
+Failure* Failure::OutOfMemoryException(intptr_t value) {
+ return Construct(OUT_OF_MEMORY_EXCEPTION, value);
}
@@ -1734,7 +1739,7 @@
if (!js_value->value()->IsString()) return false;
String* str = String::cast(js_value->value());
- if (index >= (uint32_t)str->length()) return false;
+ if (index >= static_cast<uint32_t>(str->length())) return false;
return true;
}
@@ -2546,31 +2551,26 @@
switch (type & (kStringRepresentationMask | kStringEncodingMask)) {
case kSeqStringTag | kOneByteStringTag:
visitor.VisitOneByteString(
- reinterpret_cast<const uint8_t*>(
- SeqOneByteString::cast(string)->GetChars()) + slice_offset,
- length - offset);
+ SeqOneByteString::cast(string)->GetChars() + slice_offset,
+ length - offset);
return;
case kSeqStringTag | kTwoByteStringTag:
visitor.VisitTwoByteString(
- reinterpret_cast<const uint16_t*>(
- SeqTwoByteString::cast(string)->GetChars()) + slice_offset,
- length - offset);
+ SeqTwoByteString::cast(string)->GetChars() + slice_offset,
+ length - offset);
return;
case kExternalStringTag | kOneByteStringTag:
visitor.VisitOneByteString(
- reinterpret_cast<const uint8_t*>(
- ExternalAsciiString::cast(string)->GetChars()) + slice_offset,
- length - offset);
+ ExternalAsciiString::cast(string)->GetChars() + slice_offset,
+ length - offset);
return;
case kExternalStringTag | kTwoByteStringTag:
visitor.VisitTwoByteString(
- reinterpret_cast<const uint16_t*>(
- ExternalTwoByteString::cast(string)->GetChars())
- + slice_offset,
- length - offset);
+ ExternalTwoByteString::cast(string)->GetChars() + slice_offset,
+ length - offset);
return;
case kSlicedStringTag | kOneByteStringTag:
@@ -2605,7 +2605,7 @@
void SeqOneByteString::SeqOneByteStringSet(int index, uint16_t value) {
- ASSERT(index >= 0 && index < length() && value <= kMaxAsciiCharCode);
+ ASSERT(index >= 0 && index < length() && value <= kMaxOneByteCharCode);
WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize,
static_cast<byte>(value));
}
@@ -2616,8 +2616,8 @@
}
-char* SeqOneByteString::GetChars() {
- return reinterpret_cast<char*>(GetCharsAddress());
+uint8_t* SeqOneByteString::GetChars() {
+ return reinterpret_cast<uint8_t*>(GetCharsAddress());
}
@@ -2727,8 +2727,8 @@
}
-const char* ExternalAsciiString::GetChars() {
- return resource()->data();
+const uint8_t* ExternalAsciiString::GetChars() {
+ return reinterpret_cast<const uint8_t*>(resource()->data());
}
@@ -4064,6 +4064,8 @@
ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset)
+ACCESSORS(AllocationSiteInfo, payload, Object, kPayloadOffset)
+
ACCESSORS(Script, source, Object, kSourceOffset)
ACCESSORS(Script, name, Object, kNameOffset)
ACCESSORS(Script, id, Object, kIdOffset)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 9a1a58e..c88de21 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -1002,6 +1002,22 @@
}
+void AllocationSiteInfo::AllocationSiteInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "AllocationSiteInfo");
+ PrintF(out, " - payload: ");
+ if (payload()->IsJSArray()) {
+ PrintF(out, "Array literal ");
+ payload()->ShortPrint(out);
+ PrintF(out, "\n");
+ return;
+ }
+
+ PrintF(out, "unknown payload ");
+ payload()->ShortPrint(out);
+ PrintF(out, "\n");
+}
+
+
void Script::ScriptPrint(FILE* out) {
HeapObject::PrintHeader(out, "Script");
PrintF(out, "\n - source: ");
diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h
index 925b256..309cddf 100644
--- a/src/objects-visiting-inl.h
+++ b/src/objects-visiting-inl.h
@@ -211,7 +211,8 @@
// when they might be keeping a Context alive, or when the heap is about
// to be serialized.
if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub()
- && (target->ic_state() == MEGAMORPHIC || heap->flush_monomorphic_ics() ||
+ && (target->ic_state() == MEGAMORPHIC ||
+ target->ic_state() == POLYMORPHIC || heap->flush_monomorphic_ics() ||
Serializer::enabled() || target->ic_age() != heap->global_ic_age())) {
IC::Clear(rinfo->pc());
target = Code::GetCodeFromTargetAddress(rinfo->target_address());
diff --git a/src/objects.cc b/src/objects.cc
index a97590a..2d8626b 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -903,7 +903,7 @@
result = String::cast(object);
String* first = cs->first();
int first_length = first->length();
- char* dest = SeqOneByteString::cast(result)->GetChars();
+ uint8_t* dest = SeqOneByteString::cast(result)->GetChars();
WriteToFlat(first, dest, 0, first_length);
String* second = cs->second();
WriteToFlat(second,
@@ -6561,13 +6561,13 @@
shape.representation_tag() != kSlicedStringTag);
}
if (shape.encoding_tag() == kOneByteStringTag) {
- const char* start;
+ const uint8_t* start;
if (shape.representation_tag() == kSeqStringTag) {
start = SeqOneByteString::cast(string)->GetChars();
} else {
start = ExternalAsciiString::cast(string)->GetChars();
}
- return FlatContent(Vector<const char>(start + offset, length));
+ return FlatContent(Vector<const uint8_t>(start + offset, length));
} else {
ASSERT(shape.encoding_tag() == kTwoByteStringTag);
const uc16* start;
@@ -6770,7 +6770,7 @@
ASSERT(content.IsFlat());
is_ascii_ = content.IsAscii();
if (is_ascii_) {
- start_ = content.ToAsciiVector().start();
+ start_ = content.ToOneByteVector().start();
} else {
start_ = content.ToUC16Vector().start();
}
@@ -6878,7 +6878,7 @@
if ((type & kStringRepresentationMask) != kConsStringTag) {
// Pop stack so next iteration is in correct place.
Pop();
- unsigned length = (unsigned) string->length();
+ unsigned length = static_cast<unsigned>(string->length());
// Could be a flattened ConsString.
if (length == 0) continue;
*length_out = length;
@@ -6896,7 +6896,7 @@
type = string->map()->instance_type();
if ((type & kStringRepresentationMask) != kConsStringTag) {
AdjustMaximumDepth();
- unsigned length = (unsigned) string->length();
+ unsigned length = static_cast<unsigned>(string->length());
ASSERT(length != 0);
*length_out = length;
*type_out = type;
@@ -7254,8 +7254,8 @@
// TODO(dcarney): Compare all types of flat strings with a Visitor.
if (StringShape(lhs).IsSequentialAscii() &&
StringShape(rhs).IsSequentialAscii()) {
- const char* str1 = SeqOneByteString::cast(lhs)->GetChars();
- const char* str2 = SeqOneByteString::cast(rhs)->GetChars();
+ const uint8_t* str1 = SeqOneByteString::cast(lhs)->GetChars();
+ const uint8_t* str2 = SeqOneByteString::cast(rhs)->GetChars();
return CompareRawStringContents(str1, str2, len);
}
@@ -7284,7 +7284,7 @@
}
-bool String::IsEqualTo(Vector<const char> str) {
+bool String::IsUtf8EqualTo(Vector<const char> str) {
int slen = length();
// Can't check exact length equality, but we can check bounds.
int str_len = str.length();
@@ -7313,12 +7313,12 @@
}
-bool String::IsAsciiEqualTo(Vector<const char> str) {
+bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
int slen = length();
if (str.length() != slen) return false;
FlatContent content = GetFlatContent();
if (content.IsAscii()) {
- return CompareChars(content.ToAsciiVector().start(),
+ return CompareChars(content.ToOneByteVector().start(),
str.start(), slen) == 0;
}
for (int i = 0; i < slen; i++) {
@@ -7483,6 +7483,31 @@
}
+AllocationSiteInfo* AllocationSiteInfo::FindForJSObject(JSObject* object) {
+ // Currently, AllocationSiteInfo objects are only allocated immediately
+ // after JSArrays in NewSpace, and detecting whether a JSArray has one
+ // involves carefully checking the object immediately after the JSArray
+ // (if there is one) to see if it's an AllocationSiteInfo.
+ if (FLAG_track_allocation_sites && object->GetHeap()->InNewSpace(object)) {
+ Address ptr_end = (reinterpret_cast<Address>(object) - kHeapObjectTag) +
+ object->Size();
+ if ((ptr_end + AllocationSiteInfo::kSize) <=
+ object->GetHeap()->NewSpaceTop()) {
+ // There is room in newspace for allocation info. Do we have some?
+ Map** possible_allocation_site_info_map =
+ reinterpret_cast<Map**>(ptr_end);
+ if (*possible_allocation_site_info_map ==
+ object->GetHeap()->allocation_site_info_map()) {
+ AllocationSiteInfo* info = AllocationSiteInfo::cast(
+ reinterpret_cast<Object*>(ptr_end + 1));
+ return info;
+ }
+ }
+ }
+ return NULL;
+}
+
+
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.
@@ -9009,6 +9034,7 @@
case PREMONOMORPHIC: return "PREMONOMORPHIC";
case MONOMORPHIC: return "MONOMORPHIC";
case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
+ case POLYMORPHIC: return "POLYMORPHIC";
case MEGAMORPHIC: return "MEGAMORPHIC";
case DEBUG_BREAK: return "DEBUG_BREAK";
case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
@@ -9829,6 +9855,14 @@
}
// Convert to fast double elements if appropriate.
if (HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
+ // Consider fixing the boilerplate as well if we have one.
+ ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
+ ? FAST_HOLEY_DOUBLE_ELEMENTS
+ : FAST_DOUBLE_ELEMENTS;
+
+ MaybeObject* trans = PossiblyTransitionArrayBoilerplate(to_kind);
+ if (trans->IsFailure()) return trans;
+
MaybeObject* maybe =
SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
if (maybe->IsFailure()) return maybe;
@@ -10370,6 +10404,25 @@
}
+MaybeObject* JSObject::PossiblyTransitionArrayBoilerplate(
+ ElementsKind to_kind) {
+ MaybeObject* ret = NULL;
+ if (IsJSArray()) {
+ AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(this);
+ if (info != NULL) {
+ JSObject* payload = JSObject::cast(info->payload());
+ if (payload->GetElementsKind() != to_kind) {
+ if (IsMoreGeneralElementsKindTransition(payload->GetElementsKind(),
+ to_kind)) {
+ ret = payload->TransitionElementsKind(to_kind);
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+
MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
ASSERT(!map()->is_observed());
ElementsKind from_kind = map()->elements_kind();
@@ -10380,6 +10433,9 @@
if (from_kind == to_kind) return this;
+ MaybeObject* trans = PossiblyTransitionArrayBoilerplate(to_kind);
+ if (trans->IsFailure()) return trans;
+
Isolate* isolate = GetIsolate();
if (elements() == isolate->heap()->empty_fixed_array() ||
(IsFastSmiOrObjectElementsKind(from_kind) &&
@@ -11387,7 +11443,7 @@
: string_(string), hash_field_(0), seed_(seed) { }
bool IsMatch(Object* string) {
- return String::cast(string)->IsEqualTo(string_);
+ return String::cast(string)->IsUtf8EqualTo(string_);
}
uint32_t Hash() {
@@ -11404,7 +11460,7 @@
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return Isolate::Current()->heap()->AllocateSymbol(
+ return Isolate::Current()->heap()->AllocateSymbolFromUtf8(
string_, chars_, hash_field_);
}
@@ -11443,25 +11499,25 @@
-class AsciiSymbolKey : public SequentialSymbolKey<char> {
+class OneByteSymbolKey : public SequentialSymbolKey<uint8_t> {
public:
- AsciiSymbolKey(Vector<const char> str, uint32_t seed)
- : SequentialSymbolKey<char>(str, seed) { }
+ OneByteSymbolKey(Vector<const uint8_t> str, uint32_t seed)
+ : SequentialSymbolKey<uint8_t>(str, seed) { }
bool IsMatch(Object* string) {
- return String::cast(string)->IsAsciiEqualTo(string_);
+ return String::cast(string)->IsOneByteEqualTo(string_);
}
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return HEAP->AllocateAsciiSymbol(string_, hash_field_);
+ return HEAP->AllocateOneByteSymbol(string_, hash_field_);
}
};
-class SubStringAsciiSymbolKey : public HashTableKey {
+class SubStringOneByteSymbolKey : public HashTableKey {
public:
- explicit SubStringAsciiSymbolKey(Handle<SeqOneByteString> string,
+ explicit SubStringOneByteSymbolKey(Handle<SeqOneByteString> string,
int from,
int length)
: string_(string), from_(from), length_(length) { }
@@ -11469,7 +11525,7 @@
uint32_t Hash() {
ASSERT(length_ >= 0);
ASSERT(from_ + length_ <= string_->length());
- char* chars = string_->GetChars() + from_;
+ uint8_t* chars = string_->GetChars() + from_;
hash_field_ = StringHasher::HashSequentialString(
chars, length_, string_->GetHeap()->HashSeed());
uint32_t result = hash_field_ >> String::kHashShift;
@@ -11483,14 +11539,14 @@
}
bool IsMatch(Object* string) {
- Vector<const char> chars(string_->GetChars() + from_, length_);
- return String::cast(string)->IsAsciiEqualTo(chars);
+ Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
+ return String::cast(string)->IsOneByteEqualTo(chars);
}
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- Vector<const char> chars(string_->GetChars() + from_, length_);
- return HEAP->AllocateAsciiSymbol(chars, hash_field_);
+ Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
+ return HEAP->AllocateOneByteSymbol(chars, hash_field_);
}
private:
@@ -11582,7 +11638,7 @@
? at_least_space_for
: ComputeCapacity(at_least_space_for);
if (capacity > HashTable::kMaxCapacity) {
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x10);
}
Object* obj;
@@ -11896,8 +11952,9 @@
ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
Object* value = dict->ValueAt(i);
PropertyDetails details = dict->DetailsAt(i);
- if (details.type() == CALLBACKS) {
+ if (details.type() == CALLBACKS || details.IsReadOnly()) {
// Bail out and do the sorting of undefineds and array holes in JS.
+ // Also bail out if the element is not supposed to be moved.
return Smi::FromInt(-1);
}
uint32_t key = NumberToUint32(k);
@@ -12410,9 +12467,9 @@
}
-MaybeObject* SymbolTable::LookupOneByteSymbol(Vector<const char> str,
+MaybeObject* SymbolTable::LookupOneByteSymbol(Vector<const uint8_t> str,
Object** s) {
- AsciiSymbolKey key(str, GetHeap()->HashSeed());
+ OneByteSymbolKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
@@ -12422,7 +12479,7 @@
int from,
int length,
Object** s) {
- SubStringAsciiSymbolKey key(str, from, length);
+ SubStringOneByteSymbolKey key(str, from, length);
return LookupKey(&key, s);
}
diff --git a/src/objects.h b/src/objects.h
index f1fa27a..79f1f1d 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -291,6 +291,7 @@
V(OBJECT_TEMPLATE_INFO_TYPE) \
V(SIGNATURE_INFO_TYPE) \
V(TYPE_SWITCH_INFO_TYPE) \
+ V(ALLOCATION_SITE_INFO_TYPE) \
V(SCRIPT_TYPE) \
V(CODE_CACHE_TYPE) \
V(POLYMORPHIC_CODE_CACHE_TYPE) \
@@ -444,6 +445,7 @@
V(SIGNATURE_INFO, SignatureInfo, signature_info) \
V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \
V(SCRIPT, Script, script) \
+ V(ALLOCATION_SITE_INFO, AllocationSiteInfo, allocation_site_info) \
V(CODE_CACHE, CodeCache, code_cache) \
V(POLYMORPHIC_CODE_CACHE, PolymorphicCodeCache, polymorphic_code_cache) \
V(TYPE_FEEDBACK_INFO, TypeFeedbackInfo, type_feedback_info) \
@@ -606,6 +608,7 @@
OBJECT_TEMPLATE_INFO_TYPE,
SIGNATURE_INFO_TYPE,
TYPE_SWITCH_INFO_TYPE,
+ ALLOCATION_SITE_INFO_TYPE,
SCRIPT_TYPE,
CODE_CACHE_TYPE,
POLYMORPHIC_CODE_CACHE_TYPE,
@@ -1141,7 +1144,9 @@
static inline Failure* RetryAfterGC(); // NEW_SPACE
static inline Failure* Exception();
static inline Failure* InternalError();
- static inline Failure* OutOfMemoryException();
+ // TODO(jkummerow): The value is temporary instrumentation. Remove it
+ // when it has served its purpose.
+ static inline Failure* OutOfMemoryException(intptr_t value);
// Casting.
static inline Failure* cast(MaybeObject* object);
@@ -2012,6 +2017,8 @@
ElementsKind to_kind);
MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind);
+ MUST_USE_RESULT MaybeObject* PossiblyTransitionArrayBoilerplate(
+ ElementsKind to_kind);
// Replaces an existing transition with a transition to a map with a FIELD.
MUST_USE_RESULT MaybeObject* ConvertTransitionToMapTransition(
@@ -3028,7 +3035,7 @@
// pointer *s is set to the symbol found.
MUST_USE_RESULT MaybeObject* LookupUtf8Symbol(Vector<const char> str,
Object** s);
- MUST_USE_RESULT MaybeObject* LookupOneByteSymbol(Vector<const char> str,
+ MUST_USE_RESULT MaybeObject* LookupOneByteSymbol(Vector<const uint8_t> str,
Object** s);
MUST_USE_RESULT MaybeObject* LookupSubStringOneByteSymbol(
Handle<SeqOneByteString> str,
@@ -6897,6 +6904,32 @@
};
+enum AllocationSiteInfoMode {
+ DONT_TRACK_ALLOCATION_SITE_INFO,
+ TRACK_ALLOCATION_SITE_INFO
+};
+
+
+class AllocationSiteInfo: public Struct {
+ public:
+ DECL_ACCESSORS(payload, Object)
+
+ static inline AllocationSiteInfo* cast(Object* obj);
+
+ DECLARE_PRINTER(AllocationSiteInfo)
+ DECLARE_VERIFIER(AllocationSiteInfo)
+
+ // Returns NULL if no AllocationSiteInfo is available for object.
+ static AllocationSiteInfo* FindForJSObject(JSObject* object);
+
+ static const int kPayloadOffset = HeapObject::kHeaderSize;
+ static const int kSize = kPayloadOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSiteInfo);
+};
+
+
// Representation of a slow alias as part of a non-strict arguments objects.
// For fast aliases (if HasNonStrictArgumentsElements()):
// - the parameter map contains an index into the context
@@ -7057,11 +7090,11 @@
// Returns true if the structure contains two-byte content.
bool IsTwoByte() { return state_ == TWO_BYTE; }
- // Return the ASCII content of the string. Only use if IsAscii() returns
+ // Return the one byte content of the string. Only use if IsAscii() returns
// true.
- Vector<const char> ToAsciiVector() {
+ Vector<const uint8_t> ToOneByteVector() {
ASSERT_EQ(ASCII, state_);
- return Vector<const char>::cast(buffer_);
+ return buffer_;
}
// Return the two-byte content of the string. Only use if IsTwoByte()
// returns true.
@@ -7074,15 +7107,15 @@
enum State { NON_FLAT, ASCII, TWO_BYTE };
// Constructors only used by String::GetFlatContent().
- explicit FlatContent(Vector<const char> chars)
- : buffer_(Vector<const byte>::cast(chars)),
+ explicit FlatContent(Vector<const uint8_t> chars)
+ : buffer_(chars),
state_(ASCII) { }
explicit FlatContent(Vector<const uc16> chars)
: buffer_(Vector<const byte>::cast(chars)),
state_(TWO_BYTE) { }
FlatContent() : buffer_(), state_(NON_FLAT) { }
- Vector<const byte> buffer_;
+ Vector<const uint8_t> buffer_;
State state_;
friend class String;
@@ -7113,6 +7146,8 @@
// possible.
inline bool HasOnlyAsciiChars();
+ inline bool IsOneByteConvertible();
+
// Get and set individual two byte chars in the string.
inline void Set(int index, uint16_t value);
// Get individual two byte char in the string. Repeated calls
@@ -7163,8 +7198,8 @@
// String equality operations.
inline bool Equals(String* other);
- bool IsEqualTo(Vector<const char> str);
- bool IsAsciiEqualTo(Vector<const char> str);
+ bool IsUtf8EqualTo(Vector<const char> str);
+ bool IsOneByteEqualTo(Vector<const uint8_t> str);
bool IsTwoByteEqualTo(Vector<const uc16> str);
// Return a UTF8 representation of the string. The string is null
@@ -7240,9 +7275,9 @@
// value into an array index.
static const int kMaxArrayIndexSize = 10;
- // Max ASCII char code.
- static const int kMaxAsciiCharCode = unibrow::Utf8::kMaxOneByteChar;
- static const unsigned kMaxAsciiCharCodeU = unibrow::Utf8::kMaxOneByteChar;
+ // Max char codes.
+ static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar;
+ static const uint32_t kMaxOneByteCharCodeU = unibrow::Latin1::kMaxChar;
static const int kMaxUtf16CodeUnit = 0xffff;
// Mask constant for checking if a string has a computed hash code
@@ -7327,7 +7362,7 @@
const char* start = chars;
const char* limit = chars + length;
#ifdef V8_HOST_CAN_READ_UNALIGNED
- ASSERT(kMaxAsciiCharCode == 0x7F);
+ ASSERT(unibrow::Utf8::kMaxOneByteChar == 0x7F);
const uintptr_t non_ascii_mask = kUintptrAllBitsSet / 0xFF * 0x80;
while (chars + sizeof(uintptr_t) <= limit) {
if (*reinterpret_cast<const uintptr_t*>(chars) & non_ascii_mask) {
@@ -7337,7 +7372,7 @@
}
#endif
while (chars < limit) {
- if (static_cast<uint8_t>(*chars) > kMaxAsciiCharCodeU) {
+ if (static_cast<uint8_t>(*chars) > unibrow::Utf8::kMaxOneByteChar) {
return static_cast<int>(chars - start);
}
++chars;
@@ -7349,18 +7384,23 @@
return NonAsciiStart(chars, length) >= length;
}
- static inline int NonAsciiStart(const uc16* chars, int length) {
+ static inline bool IsAscii(const uint8_t* chars, int length) {
+ return
+ NonAsciiStart(reinterpret_cast<const char*>(chars), length) >= length;
+ }
+
+ static inline int NonOneByteStart(const uc16* chars, int length) {
const uc16* limit = chars + length;
const uc16* start = chars;
while (chars < limit) {
- if (*chars > kMaxAsciiCharCodeU) return static_cast<int>(chars - start);
+ if (*chars > kMaxOneByteCharCodeU) return static_cast<int>(chars - start);
++chars;
}
return static_cast<int>(chars - start);
}
- static inline bool IsAscii(const uc16* chars, int length) {
- return NonAsciiStart(chars, length) >= length;
+ static inline bool IsOneByte(const uc16* chars, int length) {
+ return NonOneByteStart(chars, length) >= length;
}
template<class Visitor, class ConsOp>
@@ -7425,7 +7465,7 @@
// Get the address of the characters in this string.
inline Address GetCharsAddress();
- inline char* GetChars();
+ inline uint8_t* GetChars();
// Casting
static inline SeqOneByteString* cast(Object* obj);
@@ -7638,7 +7678,7 @@
// which the pointer cache has to be refreshed.
inline void update_data_cache();
- inline const char* GetChars();
+ inline const uint8_t* GetChars();
// Dispatched behavior.
inline uint16_t ExternalAsciiStringGet(int index);
diff --git a/src/parser.cc b/src/parser.cc
index 6365e41..f6f8462 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -255,7 +255,7 @@
>= static_cast<unsigned>(symbol_cache_.length())) {
if (scanner().is_literal_ascii()) {
return isolate()->factory()->LookupOneByteSymbol(
- scanner().literal_ascii_string());
+ Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
} else {
return isolate()->factory()->LookupTwoByteSymbol(
scanner().literal_utf16_string());
@@ -276,7 +276,7 @@
if (result.is_null()) {
if (scanner().is_literal_ascii()) {
result = isolate()->factory()->LookupOneByteSymbol(
- scanner().literal_ascii_string());
+ Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
} else {
result = isolate()->factory()->LookupTwoByteSymbol(
scanner().literal_utf16_string());
@@ -1429,7 +1429,7 @@
case Token::IDENTIFIER: {
Handle<String> name = ParseIdentifier(CHECK_OK);
// Handle 'module' as a context-sensitive keyword.
- if (!name->IsEqualTo(CStrVector("module"))) {
+ if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("module"))) {
names.Add(name, zone());
while (peek() == Token::COMMA) {
Consume(Token::COMMA);
@@ -4711,7 +4711,7 @@
if (!*ok) return;
Handle<String> symbol = GetSymbol(ok);
if (!*ok) return;
- if (!symbol->IsEqualTo(CStrVector(keyword))) {
+ if (!symbol->IsUtf8EqualTo(CStrVector(keyword))) {
*ok = false;
ReportUnexpectedToken(scanner().current_token());
}
diff --git a/src/regexp-macro-assembler.cc b/src/regexp-macro-assembler.cc
index ee9347a..f73726a 100644
--- a/src/regexp-macro-assembler.cc
+++ b/src/regexp-macro-assembler.cc
@@ -80,11 +80,11 @@
if (subject->IsOneByteRepresentation()) {
const byte* address;
if (StringShape(subject).IsExternal()) {
- const char* data = ExternalAsciiString::cast(subject)->GetChars();
+ const uint8_t* data = ExternalAsciiString::cast(subject)->GetChars();
address = reinterpret_cast<const byte*>(data);
} else {
ASSERT(subject->IsSeqOneByteString());
- char* data = SeqOneByteString::cast(subject)->GetChars();
+ const uint8_t* data = SeqOneByteString::cast(subject)->GetChars();
address = reinterpret_cast<const byte*>(data);
}
return address + start_index;
diff --git a/src/runtime.cc b/src/runtime.cc
index f6051ac..0b63056 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -1804,25 +1804,27 @@
result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
source,
final);
- ASSERT(!result->IsFailure());
+ // TODO(jkummerow): Turn these back into ASSERTs when we can be certain
+ // that it never fires in Release mode in the wild.
+ CHECK(!result->IsFailure());
result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
global,
final);
- ASSERT(!result->IsFailure());
+ CHECK(!result->IsFailure());
result =
regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
ignoreCase,
final);
- ASSERT(!result->IsFailure());
+ CHECK(!result->IsFailure());
result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
multiline,
final);
- ASSERT(!result->IsFailure());
+ CHECK(!result->IsFailure());
result =
regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
Smi::FromInt(0),
writable);
- ASSERT(!result->IsFailure());
+ CHECK(!result->IsFailure());
USE(result);
return regexp;
}
@@ -2405,7 +2407,7 @@
if (is_ascii_) {
Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_);
AssertNoAllocation no_alloc;
- char* char_buffer = seq->GetChars();
+ uint8_t* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_,
char_buffer,
*array_builder_.array(),
@@ -2662,7 +2664,7 @@
bool simple = false;
if (content.IsAscii()) {
simple = ParseReplacementPattern(&parts_,
- content.ToAsciiVector(),
+ content.ToOneByteVector(),
capture_count,
subject_length,
zone());
@@ -2738,7 +2740,7 @@
}
-void FindAsciiStringIndices(Vector<const char> subject,
+void FindAsciiStringIndices(Vector<const uint8_t> subject,
char pattern,
ZoneList<int>* indices,
unsigned int limit,
@@ -2746,11 +2748,11 @@
ASSERT(limit > 0);
// Collect indices of pattern in subject using memchr.
// Stop after finding at most limit values.
- const char* subject_start = reinterpret_cast<const char*>(subject.start());
- const char* subject_end = subject_start + subject.length();
- const char* pos = subject_start;
+ const uint8_t* subject_start = subject.start();
+ const uint8_t* subject_end = subject_start + subject.length();
+ const uint8_t* pos = subject_start;
while (limit > 0) {
- pos = reinterpret_cast<const char*>(
+ pos = reinterpret_cast<const uint8_t*>(
memchr(pos, pattern, subject_end - pos));
if (pos == NULL) return;
indices->Add(static_cast<int>(pos - subject_start), zone);
@@ -2813,9 +2815,10 @@
ASSERT(subject_content.IsFlat());
ASSERT(pattern_content.IsFlat());
if (subject_content.IsAscii()) {
- Vector<const char> subject_vector = subject_content.ToAsciiVector();
+ Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
if (pattern_content.IsAscii()) {
- Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
+ Vector<const uint8_t> pattern_vector =
+ pattern_content.ToOneByteVector();
if (pattern_vector.length() == 1) {
FindAsciiStringIndices(subject_vector,
pattern_vector[0],
@@ -2841,7 +2844,8 @@
} else {
Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
if (pattern_content.IsAscii()) {
- Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
+ Vector<const uint8_t> pattern_vector =
+ pattern_content.ToOneByteVector();
if (pattern_vector.length() == 1) {
FindTwoByteStringIndices(subject_vector,
pattern_vector[0],
@@ -2913,7 +2917,7 @@
static_cast<int64_t>(pattern_len)) *
static_cast<int64_t>(matches) +
static_cast<int64_t>(subject_len);
- if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException();
+ if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11);
int result_len = static_cast<int>(result_len_64);
int subject_pos = 0;
@@ -2990,7 +2994,8 @@
if (is_global &&
regexp->TypeTag() == JSRegExp::ATOM &&
simple_replace) {
- if (subject->HasOnlyAsciiChars() && replacement->HasOnlyAsciiChars()) {
+ if (subject->IsOneByteConvertible() &&
+ replacement->IsOneByteConvertible()) {
return StringReplaceAtomRegExpWithString<SeqOneByteString>(
isolate, subject, regexp, replacement, last_match_info);
} else {
@@ -3081,7 +3086,7 @@
if (is_global &&
regexp->TypeTag() == JSRegExp::ATOM) {
Handle<String> empty_string = isolate->factory()->empty_string();
- if (subject->HasOnlyAsciiChars()) {
+ if (subject->IsOneByteRepresentation()) {
return StringReplaceAtomRegExpWithString<SeqOneByteString>(
isolate,
subject,
@@ -3210,7 +3215,7 @@
ASSERT(last_match_info->HasFastObjectElements());
if (replacement->length() == 0) {
- if (subject->HasOnlyAsciiChars()) {
+ if (subject->IsOneByteConvertible()) {
return StringReplaceRegExpWithEmptyString<SeqOneByteString>(
isolate, subject, regexp, last_match_info);
} else {
@@ -3322,10 +3327,10 @@
// dispatch on type of strings
if (seq_pat.IsAscii()) {
- Vector<const char> pat_vector = seq_pat.ToAsciiVector();
+ Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
if (seq_sub.IsAscii()) {
return SearchString(isolate,
- seq_sub.ToAsciiVector(),
+ seq_sub.ToOneByteVector(),
pat_vector,
start_index);
}
@@ -3337,7 +3342,7 @@
Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
if (seq_sub.IsAscii()) {
return SearchString(isolate,
- seq_sub.ToAsciiVector(),
+ seq_sub.ToOneByteVector(),
pat_vector,
start_index);
}
@@ -3377,7 +3382,7 @@
if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
for (int i = 0; i < pattern_length; i++) {
uc16 c = pattern[i];
- if (c > String::kMaxAsciiCharCode) {
+ if (c > String::kMaxOneByteCharCode) {
return -1;
}
}
@@ -3432,9 +3437,9 @@
String::FlatContent pat_content = pat->GetFlatContent();
if (pat_content.IsAscii()) {
- Vector<const char> pat_vector = pat_content.ToAsciiVector();
+ Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
if (sub_content.IsAscii()) {
- position = StringMatchBackwards(sub_content.ToAsciiVector(),
+ position = StringMatchBackwards(sub_content.ToOneByteVector(),
pat_vector,
start_index);
} else {
@@ -3445,7 +3450,7 @@
} else {
Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
if (sub_content.IsAscii()) {
- position = StringMatchBackwards(sub_content.ToAsciiVector(),
+ position = StringMatchBackwards(sub_content.ToOneByteVector(),
pat_vector,
start_index);
} else {
@@ -4999,7 +5004,7 @@
}
-static bool AreDigits(const char*s, int from, int to) {
+static bool AreDigits(const uint8_t*s, int from, int to) {
for (int i = from; i < to; i++) {
if (s[i] < '0' || s[i] > '9') return false;
}
@@ -5008,7 +5013,7 @@
}
-static int ParseDecimalInteger(const char*s, int from, int to) {
+static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
ASSERT(to - from < 10); // Overflow is not possible.
ASSERT(from < to);
int d = s[from] - '0';
@@ -5032,7 +5037,7 @@
if (subject->IsSeqOneByteString()) {
if (len == 0) return Smi::FromInt(0);
- char const* data = SeqOneByteString::cast(subject)->GetChars();
+ uint8_t const* data = SeqOneByteString::cast(subject)->GetChars();
bool minus = (data[0] == '-');
int start_pos = (minus ? 1 : 0);
@@ -5159,7 +5164,7 @@
ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
if (escaped_length > String::kMaxLength) {
isolate->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x12);
}
}
}
@@ -5258,14 +5263,14 @@
source->TryFlatten();
- bool ascii = true;
+ bool one_byte = true;
int length = source->length();
int unescaped_length = 0;
for (int i = 0; i < length; unescaped_length++) {
int step;
- if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
- ascii = false;
+ if (Unescape(source, i, length, &step) > String::kMaxOneByteCharCode) {
+ one_byte = false;
}
i += step;
}
@@ -5276,7 +5281,7 @@
Object* o;
{ MaybeObject* maybe_o =
- ascii ?
+ one_byte ?
isolate->heap()->AllocateRawOneByteString(unescaped_length) :
isolate->heap()->AllocateRawTwoByteString(unescaped_length);
if (!maybe_o->ToObject(&o)) return maybe_o;
@@ -5527,8 +5532,9 @@
return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
flat.ToUC16Vector());
} else {
- return QuoteJsonString<char, SeqOneByteString, false>(isolate,
- flat.ToAsciiVector());
+ return QuoteJsonString<uint8_t, SeqOneByteString, false>(
+ isolate,
+ flat.ToOneByteVector());
}
}
@@ -5550,8 +5556,9 @@
return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
flat.ToUC16Vector());
} else {
- return QuoteJsonString<char, SeqOneByteString, true>(isolate,
- flat.ToAsciiVector());
+ return QuoteJsonString<uint8_t, SeqOneByteString, true>(
+ isolate,
+ flat.ToOneByteVector());
}
}
@@ -5592,9 +5599,10 @@
write_cursor,
content.ToUC16Vector());
} else {
- write_cursor = WriteQuoteJsonString<Char, char>(isolate,
- write_cursor,
- content.ToAsciiVector());
+ write_cursor =
+ WriteQuoteJsonString<Char, uint8_t>(isolate,
+ write_cursor,
+ content.ToOneByteVector());
}
}
*(write_cursor++) = ']';
@@ -5766,7 +5774,7 @@
current_length += char_length;
if (current_length > Smi::kMaxValue) {
isolate->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x13);
}
}
// Try again with the real length.
@@ -5933,6 +5941,7 @@
// Assume that the string is not empty; we need this assumption later
if (length == 0) return s;
+#ifndef ENABLE_LATIN_1
// Simpler handling of ASCII strings.
//
// NOTE: This assumes that the upper/lower case of an ASCII
@@ -5946,9 +5955,12 @@
}
SeqOneByteString* result = SeqOneByteString::cast(o);
bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
- result->GetChars(), SeqOneByteString::cast(s)->GetChars(), length);
+ reinterpret_cast<char*>(result->GetChars()),
+ reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
+ length);
return has_changed_character ? result : s;
}
+#endif
Object* answer;
{ MaybeObject* maybe_answer =
@@ -6107,7 +6119,7 @@
// not in the cache and fills the remainder with smi zeros. Returns
// the length of the successfully copied prefix.
static int CopyCachedAsciiCharsToArray(Heap* heap,
- const char* chars,
+ const uint8_t* chars,
FixedArray* elements,
int length) {
AssertNoAllocation no_gc;
@@ -6158,7 +6170,7 @@
elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
String::FlatContent content = s->GetFlatContent();
if (content.IsAscii()) {
- Vector<const char> chars = content.ToAsciiVector();
+ Vector<const uint8_t> chars = content.ToOneByteVector();
// Note, this will initialize all elements (not only the prefix)
// to prevent GC from seeing partially initialized array.
position = CopyCachedAsciiCharsToArray(isolate->heap(),
@@ -6434,7 +6446,7 @@
CONVERT_ARG_CHECKED(JSArray, array, 0);
if (!args[1]->IsSmi()) {
isolate->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x14);
}
int array_length = args.smi_at(1);
CONVERT_ARG_CHECKED(String, special, 2);
@@ -6461,7 +6473,7 @@
if (first->IsString()) return first;
}
- bool ascii = special->HasOnlyAsciiChars();
+ bool one_byte = special->IsOneByteConvertible();
int position = 0;
for (int i = 0; i < array_length; i++) {
int increment = 0;
@@ -6502,8 +6514,8 @@
String* element = String::cast(elt);
int element_length = element->length();
increment = element_length;
- if (ascii && !element->HasOnlyAsciiChars()) {
- ascii = false;
+ if (one_byte && !element->IsOneByteConvertible()) {
+ one_byte = false;
}
} else {
ASSERT(!elt->IsTheHole());
@@ -6511,7 +6523,7 @@
}
if (increment > String::kMaxLength - position) {
isolate->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x15);
}
position += increment;
}
@@ -6519,7 +6531,7 @@
int length = position;
Object* object;
- if (ascii) {
+ if (one_byte) {
{ MaybeObject* maybe_object =
isolate->heap()->AllocateRawOneByteString(length);
if (!maybe_object->ToObject(&object)) return maybe_object;
@@ -6551,7 +6563,7 @@
CONVERT_ARG_CHECKED(JSArray, array, 0);
if (!args[1]->IsSmi()) {
isolate->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x16);
}
int array_length = args.smi_at(1);
CONVERT_ARG_CHECKED(String, separator, 2);
@@ -6576,7 +6588,7 @@
(String::kMaxLength + separator_length - 1) / separator_length;
if (max_nof_separators < (array_length - 1)) {
isolate->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x17);
}
int length = (array_length - 1) * separator_length;
for (int i = 0; i < array_length; i++) {
@@ -6589,7 +6601,7 @@
int increment = element->length();
if (increment > String::kMaxLength - length) {
isolate->context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
+ return Failure::OutOfMemoryException(0x18);
}
length += increment;
}
@@ -6624,7 +6636,8 @@
}
ASSERT(sink == end);
- ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
+ // Use %_FastAsciiArrayJoin instead.
+ ASSERT(!answer->IsOneByteRepresentation());
return answer;
}
@@ -6740,12 +6753,13 @@
if (result_allocation->IsFailure()) return result_allocation;
SeqOneByteString* result_string =
SeqOneByteString::cast(result_allocation->ToObjectUnchecked());
- JoinSparseArrayWithSeparator<char>(elements,
- elements_length,
- array_length,
- separator,
- Vector<char>(result_string->GetChars(),
- string_length));
+ JoinSparseArrayWithSeparator<uint8_t>(elements,
+ elements_length,
+ array_length,
+ separator,
+ Vector<uint8_t>(
+ result_string->GetChars(),
+ string_length));
return result_string;
} else {
MaybeObject* result_allocation =
@@ -6993,9 +7007,9 @@
String::FlatContent x_content = x->GetFlatContent();
String::FlatContent y_content = y->GetFlatContent();
if (x_content.IsAscii()) {
- Vector<const char> x_chars = x_content.ToAsciiVector();
+ Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
if (y_content.IsAscii()) {
- Vector<const char> y_chars = y_content.ToAsciiVector();
+ Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
} else {
Vector<const uc16> y_chars = y_content.ToUC16Vector();
@@ -7004,7 +7018,7 @@
} else {
Vector<const uc16> x_chars = x_content.ToUC16Vector();
if (y_content.IsAscii()) {
- Vector<const char> y_chars = y_content.ToAsciiVector();
+ Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
} else {
Vector<const uc16> y_chars = y_content.ToUC16Vector();
@@ -7889,7 +7903,7 @@
};
-RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyICMiss) {
+RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) {
HandleScope scope(isolate);
ASSERT(args.length() == 0);
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
@@ -8016,7 +8030,7 @@
if (args.length() == 2 &&
unoptimized->kind() == Code::FUNCTION) {
CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
- CHECK(type->IsEqualTo(CStrVector("osr")));
+ CHECK(type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr")));
isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
unoptimized->set_allow_osr_at_loop_nesting_level(
Code::kMaxLoopNestingMarker);
@@ -8954,7 +8968,7 @@
bool result;
String::FlatContent str_content = str->GetFlatContent();
if (str_content.IsAscii()) {
- result = DateParser::Parse(str_content.ToAsciiVector(),
+ result = DateParser::Parse(str_content.ToOneByteVector(),
output_array,
isolate->unicode_cache());
} else {
@@ -13242,6 +13256,15 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
+ FlattenString(str);
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
// This is only called from codegen, so checks might be more lax.
CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
@@ -13403,8 +13426,8 @@
CONVERT_ARG_CHECKED(JSArray, elms, 1);
String::FlatContent format_content = format->GetFlatContent();
RUNTIME_ASSERT(format_content.IsAscii());
- Vector<const char> chars = format_content.ToAsciiVector();
- LOGGER->LogRuntime(chars, elms);
+ Vector<const uint8_t> chars = format_content.ToOneByteVector();
+ LOGGER->LogRuntime(Vector<const char>::cast(chars), elms);
return isolate->heap()->undefined_value();
}
diff --git a/src/runtime.h b/src/runtime.h
index 47102a0..b72813d 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -89,7 +89,7 @@
F(ForceParallelRecompile, 1, 1) \
F(InstallRecompiledCode, 1, 1) \
F(NotifyDeoptimized, 1, 1) \
- F(NotifyICMiss, 0, 1) \
+ F(NotifyStubFailure, 0, 1) \
F(NotifyOSR, 0, 1) \
F(DeoptimizeFunction, 1, 1) \
F(ClearFunctionTypeFeedback, 1, 1) \
@@ -104,6 +104,7 @@
F(StoreArrayLiteralElement, 5, 1) \
F(DebugCallbackSupportsStepping, 1, 1) \
F(DebugPrepareStepInIfStepping, 1, 1) \
+ F(FlattenString, 1, 1) \
\
/* Array join support */ \
F(PushIfAbsent, 2, 1) \
diff --git a/src/scanner.h b/src/scanner.h
index 0a560e3..a454750 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -183,9 +183,9 @@
INLINE(void AddChar(uint32_t code_unit)) {
if (position_ >= backing_store_.length()) ExpandBuffer();
if (is_ascii_) {
- if (code_unit < kMaxAsciiCharCodeU) {
+ if (code_unit <= unibrow::Latin1::kMaxChar) {
backing_store_[position_] = static_cast<byte>(code_unit);
- position_ += kASCIISize;
+ position_ += kOneByteSize;
return;
}
ConvertToUtf16();
@@ -250,7 +250,7 @@
} else {
new_store = backing_store_;
}
- char* src = reinterpret_cast<char*>(backing_store_.start());
+ uint8_t* src = backing_store_.start();
uc16* dst = reinterpret_cast<uc16*>(new_store.start());
for (int i = position_ - 1; i >= 0; i--) {
dst[i] = src[i];
diff --git a/src/string-search.h b/src/string-search.h
index 8c3456a..86237f3 100644
--- a/src/string-search.h
+++ b/src/string-search.h
@@ -53,7 +53,11 @@
// a potentially less efficient searching, but is a safe approximation.
// For needles using only characters in the same Unicode 256-code point page,
// there is no search speed degradation.
+#ifndef ENABLE_LATIN_1
static const int kAsciiAlphabetSize = 128;
+#else
+ static const int kAsciiAlphabetSize = 256;
+#endif
static const int kUC16AlphabetSize = Isolate::kUC16AlphabetSize;
// Bad-char shift table stored in the state. It's length is the alphabet size.
@@ -61,12 +65,12 @@
// to compensate for the algorithmic overhead compared to simple brute force.
static const int kBMMinPatternLength = 7;
- static inline bool IsAsciiString(Vector<const char>) {
+ static inline bool IsOneByteString(Vector<const uint8_t> string) {
return true;
}
- static inline bool IsAsciiString(Vector<const uc16> string) {
- return String::IsAscii(string.start(), string.length());
+ static inline bool IsOneByteString(Vector<const uc16> string) {
+ return String::IsOneByte(string.start(), string.length());
}
friend class Isolate;
@@ -81,7 +85,7 @@
pattern_(pattern),
start_(Max(0, pattern.length() - kBMMaxShift)) {
if (sizeof(PatternChar) > sizeof(SubjectChar)) {
- if (!IsAsciiString(pattern_)) {
+ if (!IsOneByteString(pattern_)) {
strategy_ = &FailSearch;
return;
}
@@ -150,13 +154,25 @@
void PopulateBoyerMooreTable();
+ static inline bool exceedsOneByte(uint8_t c) {
+#ifdef ENABLE_LATIN_1
+ return false;
+#else
+ return c > String::kMaxOneByteCharCodeU;
+#endif
+ }
+
+ static inline bool exceedsOneByte(uint16_t c) {
+ return c > String::kMaxOneByteCharCodeU;
+ }
+
static inline int CharOccurrence(int* bad_char_occurrence,
SubjectChar char_code) {
if (sizeof(SubjectChar) == 1) {
return bad_char_occurrence[static_cast<int>(char_code)];
}
if (sizeof(PatternChar) == 1) {
- if (static_cast<unsigned int>(char_code) > String::kMaxAsciiCharCodeU) {
+ if (exceedsOneByte(char_code)) {
return -1;
}
return bad_char_occurrence[static_cast<unsigned int>(char_code)];
@@ -223,7 +239,7 @@
return static_cast<int>(pos - subject.start());
} else {
if (sizeof(PatternChar) > sizeof(SubjectChar)) {
- if (static_cast<uc16>(pattern_first_char) > String::kMaxAsciiCharCodeU) {
+ if (exceedsOneByte(pattern_first_char)) {
return -1;
}
}
diff --git a/src/string.js b/src/string.js
index d9ca035..60a5abe 100644
--- a/src/string.js
+++ b/src/string.js
@@ -825,6 +825,7 @@
var code = %_Arguments(i);
if (!%_IsSmi(code)) code = ToNumber(code) & 0xffff;
if (code < 0) code = code & 0xffff;
+ // TODO(dcarney): Fix for Latin-1.
if (code > 0x7f) break;
%_OneByteSeqStringSetChar(one_byte, i, code);
}
diff --git a/src/type-info.cc b/src/type-info.cc
index 7a9a5de..00e8ee8 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -111,14 +111,11 @@
}
-bool TypeFeedbackOracle::LoadIsMegamorphicWithTypeInfo(Property* expr) {
+bool TypeFeedbackOracle::LoadIsPolymorphic(Property* expr) {
Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId());
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::cast(map_or_code);
- Builtins* builtins = isolate_->builtins();
- return code->is_keyed_load_stub() &&
- *code != builtins->builtin(Builtins::kKeyedLoadIC_Generic) &&
- code->ic_state() == MEGAMORPHIC;
+ return code->is_keyed_load_stub() && code->ic_state() == POLYMORPHIC;
}
return false;
}
@@ -145,19 +142,15 @@
}
-bool TypeFeedbackOracle::StoreIsMegamorphicWithTypeInfo(TypeFeedbackId ast_id) {
+bool TypeFeedbackOracle::StoreIsPolymorphic(TypeFeedbackId ast_id) {
Handle<Object> map_or_code = GetInfo(ast_id);
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::cast(map_or_code);
- Builtins* builtins = isolate_->builtins();
bool allow_growth =
Code::GetKeyedAccessGrowMode(code->extra_ic_state()) ==
ALLOW_JSARRAY_GROWTH;
- return code->is_keyed_store_stub() &&
- !allow_growth &&
- *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic) &&
- *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic_Strict) &&
- code->ic_state() == MEGAMORPHIC;
+ return code->is_keyed_store_stub() && !allow_growth &&
+ code->ic_state() == POLYMORPHIC;
}
return false;
}
@@ -667,7 +660,7 @@
case Code::KEYED_LOAD_IC:
case Code::KEYED_STORE_IC:
if (target->ic_state() == MONOMORPHIC ||
- target->ic_state() == MEGAMORPHIC) {
+ target->ic_state() == POLYMORPHIC) {
SetInfo(ast_id, target);
}
break;
diff --git a/src/type-info.h b/src/type-info.h
index 8b2ec49..330ecd3 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -242,9 +242,9 @@
bool LoadIsMonomorphicNormal(Property* expr);
bool LoadIsUninitialized(Property* expr);
- bool LoadIsMegamorphicWithTypeInfo(Property* expr);
+ bool LoadIsPolymorphic(Property* expr);
bool StoreIsMonomorphicNormal(TypeFeedbackId ast_id);
- bool StoreIsMegamorphicWithTypeInfo(TypeFeedbackId ast_id);
+ bool StoreIsPolymorphic(TypeFeedbackId ast_id);
bool CallIsMonomorphic(Call* expr);
bool CallNewIsMonomorphic(CallNew* expr);
bool ObjectLiteralStoreIsMonomorphic(ObjectLiteral::Property* prop);
diff --git a/src/unicode.h b/src/unicode.h
index 626d988..61dbab4 100644
--- a/src/unicode.h
+++ b/src/unicode.h
@@ -133,6 +133,14 @@
}
};
+class Latin1 {
+ public:
+#ifndef ENABLE_LATIN_1
+ static const unsigned kMaxChar = 0x7f;
+#else
+ static const unsigned kMaxChar = 0xff;
+#endif
+};
class Utf8 {
public:
diff --git a/src/utils.h b/src/utils.h
index d964983..9080bd6 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -304,7 +304,7 @@
hash = hash ^ (hash >> 11);
hash = hash + (hash << 6);
hash = hash ^ (hash >> 22);
- return (uint32_t) hash;
+ return static_cast<uint32_t>(hash);
}
@@ -523,12 +523,21 @@
};
#define STATIC_ASCII_VECTOR(x) \
- v8::internal::Vector<const char>(x, ARRAY_SIZE(x)-1)
+ v8::internal::Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(x), \
+ ARRAY_SIZE(x)-1)
inline Vector<const char> CStrVector(const char* data) {
return Vector<const char>(data, StrLength(data));
}
+inline Vector<const uint8_t> OneByteVector(const char* data, int length) {
+ return Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), length);
+}
+
+inline Vector<const uint8_t> OneByteVector(const char* data) {
+ return OneByteVector(data, StrLength(data));
+}
+
inline Vector<char> MutableCStrVector(char* data) {
return Vector<char>(data, StrLength(data));
}
@@ -767,7 +776,9 @@
// Compare ASCII/16bit chars to ASCII/16bit chars.
template <typename lchar, typename rchar>
-inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
+inline int CompareCharsUnsigned(const lchar* lhs,
+ const rchar* rhs,
+ int chars) {
const lchar* limit = lhs + chars;
#ifdef V8_HOST_CAN_READ_UNALIGNED
if (sizeof(*lhs) == sizeof(*rhs)) {
@@ -792,6 +803,33 @@
return 0;
}
+template<typename lchar, typename rchar>
+inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
+ ASSERT(sizeof(lchar) <= 2);
+ ASSERT(sizeof(rchar) <= 2);
+ if (sizeof(lchar) == 1) {
+ if (sizeof(rchar) == 1) {
+ return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs),
+ reinterpret_cast<const uint8_t*>(rhs),
+ chars);
+ } else {
+ return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs),
+ reinterpret_cast<const uint16_t*>(rhs),
+ chars);
+ }
+ } else {
+ if (sizeof(rchar) == 1) {
+ return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs),
+ reinterpret_cast<const uint8_t*>(rhs),
+ chars);
+ } else {
+ return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs),
+ reinterpret_cast<const uint16_t*>(rhs),
+ chars);
+ }
+ }
+}
+
// Calculate 10^exponent.
inline int TenToThe(int exponent) {
diff --git a/src/v8conversions.cc b/src/v8conversions.cc
index 26a4868..900b62d 100644
--- a/src/v8conversions.cc
+++ b/src/v8conversions.cc
@@ -85,8 +85,8 @@
StringShape shape(str);
// TODO(dcarney): Use a Visitor here.
if (shape.IsSequentialAscii()) {
- const char* begin = SeqOneByteString::cast(str)->GetChars();
- const char* end = begin + str->length();
+ const uint8_t* begin = SeqOneByteString::cast(str)->GetChars();
+ const uint8_t* end = begin + str->length();
return InternalStringToDouble(unicode_cache, begin, end, flags,
empty_string_val);
} else if (shape.IsSequentialTwoByte()) {
@@ -112,8 +112,8 @@
StringShape shape(str);
// TODO(dcarney): Use a Visitor here.
if (shape.IsSequentialAscii()) {
- const char* begin = SeqOneByteString::cast(str)->GetChars();
- const char* end = begin + str->length();
+ const uint8_t* begin = SeqOneByteString::cast(str)->GetChars();
+ const uint8_t* end = begin + str->length();
return InternalStringToInt(unicode_cache, begin, end, radix);
} else if (shape.IsSequentialTwoByte()) {
const uc16* begin = SeqTwoByteString::cast(str)->GetChars();
diff --git a/src/v8globals.h b/src/v8globals.h
index 5920d33..085d67b 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -260,6 +260,8 @@
// Like MONOMORPHIC but check failed due to prototype.
MONOMORPHIC_PROTOTYPE_FAILURE,
// Multiple receiver types have been seen.
+ POLYMORPHIC,
+ // Many receiver types have been seen.
MEGAMORPHIC,
// Special states for debug break or step in prepare stubs.
DEBUG_BREAK,
diff --git a/src/v8utils.h b/src/v8utils.h
index 9072b4e..2064c5a 100644
--- a/src/v8utils.h
+++ b/src/v8utils.h
@@ -202,13 +202,44 @@
bool verbose = true);
+template <typename sourcechar, typename sinkchar>
+INLINE(static void CopyCharsUnsigned(sinkchar* dest,
+ const sourcechar* src,
+ int chars));
+
// Copy from ASCII/16bit chars to ASCII/16bit chars.
template <typename sourcechar, typename sinkchar>
INLINE(void CopyChars(sinkchar* dest, const sourcechar* src, int chars));
+template<typename sourcechar, typename sinkchar>
+void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
+ ASSERT(sizeof(sourcechar) <= 2);
+ ASSERT(sizeof(sinkchar) <= 2);
+ if (sizeof(sinkchar) == 1) {
+ if (sizeof(sourcechar) == 1) {
+ CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest),
+ reinterpret_cast<const uint8_t*>(src),
+ chars);
+ } else {
+ CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest),
+ reinterpret_cast<const uint16_t*>(src),
+ chars);
+ }
+ } else {
+ if (sizeof(sourcechar) == 1) {
+ CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest),
+ reinterpret_cast<const uint8_t*>(src),
+ chars);
+ } else {
+ CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest),
+ reinterpret_cast<const uint16_t*>(src),
+ chars);
+ }
+ }
+}
template <typename sourcechar, typename sinkchar>
-void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
+void CopyCharsUnsigned(sinkchar* dest, const sourcechar* src, int chars) {
sinkchar* limit = dest + chars;
#ifdef V8_HOST_CAN_READ_UNALIGNED
if (sizeof(*dest) == sizeof(*src)) {
diff --git a/src/version.cc b/src/version.cc
index f203b64..25854d2 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 3
#define MINOR_VERSION 16
-#define BUILD_NUMBER 2
+#define BUILD_NUMBER 3
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index e156dfd..52c81e2 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -646,7 +646,7 @@
#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
-void Builtins::Generate_NotifyICMiss(MacroAssembler* masm) {
+void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
@@ -655,7 +655,7 @@
// stubs that tail call the runtime on deopts passing their parameters in
// registers.
__ Pushad();
- __ CallRuntime(Runtime::kNotifyICMiss, 0);
+ __ CallRuntime(Runtime::kNotifyStubFailure, 0);
__ Popad();
// Tear down internal frame.
}
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 650cf5d..3f17d03 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -44,7 +44,7 @@
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
- isolate->builtins()->KeyedLoadIC_Miss();
+ FUNCTION_ADDR(KeyedLoadIC_Miss);
}
@@ -316,6 +316,7 @@
MacroAssembler* masm,
int length,
FastCloneShallowArrayStub::Mode mode,
+ AllocationSiteInfoMode allocation_site_info_mode,
Label* fail) {
// Registers on entry:
//
@@ -329,7 +330,12 @@
? FixedDoubleArray::SizeFor(length)
: FixedArray::SizeFor(length);
}
- int size = JSArray::kSize + elements_size;
+ int size = JSArray::kSize;
+ int allocation_info_start = size;
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ size += AllocationSiteInfo::kSize;
+ }
+ size += elements_size;
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
@@ -339,6 +345,12 @@
}
__ AllocateInNewSpace(size, rax, rbx, rdx, fail, flags);
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ LoadRoot(kScratchRegister, Heap::kAllocationSiteInfoMapRootIndex);
+ __ movq(FieldOperand(rax, allocation_info_start), kScratchRegister);
+ __ movq(FieldOperand(rax, allocation_info_start + kPointerSize), rcx);
+ }
+
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length == 0)) {
@@ -351,7 +363,11 @@
// Get hold of the elements array of the boilerplate and setup the
// elements pointer in the resulting object.
__ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
- __ lea(rdx, Operand(rax, JSArray::kSize));
+ if (allocation_site_info_mode == TRACK_ALLOCATION_SITE_INFO) {
+ __ lea(rdx, Operand(rax, JSArray::kSize + AllocationSiteInfo::kSize));
+ } else {
+ __ lea(rdx, Operand(rax, JSArray::kSize));
+ }
__ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
// Copy the elements array.
@@ -398,6 +414,13 @@
FastCloneShallowArrayStub::Mode mode = mode_;
// rcx is boilerplate object.
Factory* factory = masm->isolate()->factory();
+ AllocationSiteInfoMode allocation_site_info_mode =
+ DONT_TRACK_ALLOCATION_SITE_INFO;
+ if (mode == CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO) {
+ mode = CLONE_ANY_ELEMENTS;
+ allocation_site_info_mode = TRACK_ALLOCATION_SITE_INFO;
+ }
+
if (mode == CLONE_ANY_ELEMENTS) {
Label double_elements, check_fast_elements;
__ movq(rbx, FieldOperand(rcx, JSArray::kElementsOffset));
@@ -405,7 +428,9 @@
factory->fixed_cow_array_map());
__ j(not_equal, &check_fast_elements);
GenerateFastCloneShallowArrayCommon(masm, 0,
- COPY_ON_WRITE_ELEMENTS, &slow_case);
+ COPY_ON_WRITE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
__ ret(3 * kPointerSize);
__ bind(&check_fast_elements);
@@ -413,7 +438,9 @@
factory->fixed_array_map());
__ j(not_equal, &double_elements);
GenerateFastCloneShallowArrayCommon(masm, length_,
- CLONE_ELEMENTS, &slow_case);
+ CLONE_ELEMENTS,
+ allocation_site_info_mode,
+ &slow_case);
__ ret(3 * kPointerSize);
__ bind(&double_elements);
@@ -443,7 +470,8 @@
__ pop(rcx);
}
- GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
+ GenerateFastCloneShallowArrayCommon(masm, length_, mode,
+ allocation_site_info_mode, &slow_case);
__ ret(3 * kPointerSize);
__ bind(&slow_case);
@@ -3899,6 +3927,19 @@
}
+static void JumpIfOOM(MacroAssembler* masm,
+ Register value,
+ Register scratch,
+ Label* oom_label) {
+ __ movq(scratch, value);
+ STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
+ STATIC_ASSERT(kFailureTag == 3);
+ __ and_(scratch, Immediate(0xf));
+ __ cmpq(scratch, Immediate(0xf));
+ __ j(equal, oom_label);
+}
+
+
void CEntryStub::GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
Label* throw_termination_exception,
@@ -4012,9 +4053,7 @@
__ j(zero, &retry, Label::kNear);
// Special handling of out of memory exceptions.
- __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE64);
- __ cmpq(rax, kScratchRegister);
- __ j(equal, throw_out_of_memory_exception);
+ JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
ExternalReference pending_exception_address(
@@ -4111,7 +4150,10 @@
// Set pending exception and rax to out of memory exception.
ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
isolate);
- __ movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE64);
+ Label already_have_failure;
+ JumpIfOOM(masm, rax, kScratchRegister, &already_have_failure);
+ __ movq(rax, Failure::OutOfMemoryException(0x1), RelocInfo::NONE64);
+ __ bind(&already_have_failure);
__ Store(pending_exception, rax);
// Fall through to the next label.
@@ -4534,7 +4576,7 @@
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
// Fast case of Heap::LookupSingleCharacterStringFromCode.
__ JumpIfNotSmi(code_, &slow_case_);
- __ SmiCompare(code_, Smi::FromInt(String::kMaxAsciiCharCode));
+ __ SmiCompare(code_, Smi::FromInt(String::kMaxOneByteCharCode));
__ j(above, &slow_case_);
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
@@ -5445,16 +5487,32 @@
// Compare lengths (precomputed).
__ bind(&compare_lengths);
__ SmiTest(length_difference);
+#ifndef ENABLE_LATIN_1
__ j(not_zero, &result_not_equal, Label::kNear);
+#else
+ Label length_not_equal;
+ __ j(not_zero, &length_not_equal, Label::kNear);
+#endif
// Result is EQUAL.
__ Move(rax, Smi::FromInt(EQUAL));
__ ret(0);
Label result_greater;
+#ifdef ENABLE_LATIN_1
+ Label result_less;
+ __ bind(&length_not_equal);
+ __ j(greater, &result_greater, Label::kNear);
+ __ jmp(&result_less, Label::kNear);
+#endif
__ bind(&result_not_equal);
// Unequal comparison of left to right, either character or length.
+#ifndef ENABLE_LATIN_1
__ j(greater, &result_greater, Label::kNear);
+#else
+ __ j(above, &result_greater, Label::kNear);
+ __ bind(&result_less);
+#endif
// Result is LESS.
__ Move(rax, Smi::FromInt(LESS));
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 63f3ac4..0b2480a 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -283,6 +283,10 @@
// The fail label is not actually used since we do not allocate.
Label allocated, new_backing_store, only_change_map, done;
+ if (FLAG_track_allocation_sites) {
+ masm->TestJSArrayForAllocationSiteInfo(rdx, rdi, fail);
+ }
+
// Check for empty arrays, which only require a map transition and no changes
// to the backing store.
__ movq(r8, FieldOperand(rdx, JSObject::kElementsOffset));
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index c719bf8..79c8cd1 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -454,35 +454,39 @@
// FROM TO <-rbp
// | .... | | .... |
// +-------------------------+ +-------------------------+
- // | JSFunction continuation | | JSFunction continuation |
+ // | JSFunction continuation | | parameter 1 |
+ // +-------------------------+ +-------------------------+
+ // | | saved frame (rbp) | | .... |
+ // | +=========================+<-rbp +-------------------------+
+ // | | JSFunction context | | parameter n |
+ // v +-------------------------+ +-------------------------|
+ // | COMPILED_STUB marker | | JSFunction continuation |
// +-------------------------+ +-------------------------+<-rsp
- // | | saved frame (rbp) |
- // | +=========================+<-rbp
- // | | JSFunction context |
- // v +-------------------------+
- // | COMPILED_STUB marker | rbp = saved frame
- // +-------------------------+ rsi = JSFunction context
- // | |
- // | ... |
- // | |
- // +-------------------------+<-rsp
+ // | | rax = number of parameters
+ // | ... | rbx = failure handler address
+ // | | rbp = saved frame
+ // +-------------------------+<-rsp rsi = JSFunction context
//
//
- int output_frame_size = 1 * kPointerSize;
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, 0);
- Code* notify_miss =
- isolate_->builtins()->builtin(Builtins::kNotifyICMiss);
- output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
- output_frame->SetContinuation(
- reinterpret_cast<intptr_t>(notify_miss->entry()));
ASSERT(compiled_code_->kind() == Code::COMPILED_STUB);
int major_key = compiled_code_->major_key();
CodeStubInterfaceDescriptor* descriptor =
isolate_->code_stub_interface_descriptor(major_key);
- Handle<Code> miss_ic(descriptor->deoptimization_handler_);
- output_frame->SetPc(reinterpret_cast<intptr_t>(miss_ic->instruction_start()));
+
+ int output_frame_size =
+ (1 + descriptor->register_param_count_) * kPointerSize;
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, 0);
+ Code* notify_failure =
+ isolate_->builtins()->builtin(Builtins::kNotifyStubFailure);
+ output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
+ output_frame->SetContinuation(
+ reinterpret_cast<intptr_t>(notify_failure->entry()));
+
+ Code* code;
+ CEntryStub(1, kDontSaveFPRegs).FindCodeInCache(&code, isolate_);
+ output_frame->SetPc(reinterpret_cast<intptr_t>(code->instruction_start()));
unsigned input_frame_size = input_->GetFrameSize();
intptr_t value = input_->GetFrameSlot(input_frame_size - kPointerSize);
output_frame->SetFrameSlot(0, value);
@@ -492,20 +496,22 @@
value = input_->GetFrameSlot(input_frame_size - 3 * kPointerSize);
output_frame->SetRegister(rsi.code(), value);
- Translation::Opcode opcode =
- static_cast<Translation::Opcode>(iterator->Next());
- ASSERT(opcode == Translation::REGISTER);
- USE(opcode);
- int input_reg = iterator->Next();
- intptr_t input_value = input_->GetRegister(input_reg);
- output_frame->SetRegister(rdx.code(), input_value);
+ int parameter_offset = kPointerSize * descriptor->register_param_count_;
+ for (int i = 0; i < descriptor->register_param_count_; ++i) {
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ ASSERT(opcode == Translation::REGISTER);
+ USE(opcode);
+ int input_reg = iterator->Next();
+ intptr_t reg_value = input_->GetRegister(input_reg);
+ output_frame->SetFrameSlot(parameter_offset, reg_value);
+ parameter_offset -= kPointerSize;
+ }
- int32_t next = iterator->Next();
- opcode = static_cast<Translation::Opcode>(next);
- ASSERT(opcode == Translation::REGISTER);
- input_reg = iterator->Next();
- input_value = input_->GetRegister(input_reg);
- output_frame->SetRegister(rax.code(), input_value);
+ intptr_t handler =
+ reinterpret_cast<intptr_t>(descriptor->deoptimization_handler_);
+ output_frame->SetRegister(rax.code(), descriptor->register_param_count_);
+ output_frame->SetRegister(rbx.code(), handler);
ASSERT(frame_index == 0);
output_[frame_index] = output_frame;
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 97ec4b1..6f18c19 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -127,7 +127,7 @@
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
- info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+ info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
__ int3();
}
#endif
@@ -1703,6 +1703,15 @@
FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
: FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
+
+ // Tracking allocation info allows us to pre-transition later if it makes
+ // sense.
+ if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS &&
+ FLAG_track_allocation_sites) {
+ mode = FastCloneShallowArrayStub::
+ CLONE_ANY_ELEMENTS_WITH_ALLOCATION_SITE_INFO;
+ }
+
FastCloneShallowArrayStub stub(mode, length);
__ CallStub(&stub);
}
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 641e243..f3061af 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -576,7 +576,7 @@
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -619,7 +619,7 @@
1);
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -1278,7 +1278,7 @@
__ movq(rax, unmapped_location);
__ Ret();
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -1317,7 +1317,7 @@
INLINE_SMI_CHECK);
__ Ret();
__ bind(&slow);
- GenerateMiss(masm, false);
+ GenerateMiss(masm, MISS);
}
@@ -1411,7 +1411,7 @@
}
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -1427,7 +1427,7 @@
__ push(rbx); // return address
// Perform tail call to the entry.
- ExternalReference ref = force_generic
+ ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
@@ -1638,7 +1638,7 @@
}
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@@ -1653,7 +1653,7 @@
__ push(rbx); // return address
// Do tail-call to runtime routine.
- ExternalReference ref = force_generic
+ ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index d64d4ff..8c4dafa 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -124,7 +124,7 @@
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
- info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+ info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
__ int3();
}
#endif
@@ -2224,7 +2224,7 @@
__ JumpIfSmi(input, is_false);
- if (class_name->IsEqualTo(CStrVector("Function"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
// Assuming the following assertions, we can use the same compares to test
// for both being a function type and being in the object type range.
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
@@ -2255,7 +2255,7 @@
// Objects with a non-function constructor have class 'Object'.
__ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
- if (class_name->IsEqualTo(CStrVector("Object"))) {
+ if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
__ j(not_equal, is_true);
} else {
__ j(not_equal, is_false);
@@ -4249,7 +4249,7 @@
Register result = ToRegister(instr->result());
ASSERT(!char_code.is(result));
- __ cmpl(char_code, Immediate(String::kMaxAsciiCharCode));
+ __ cmpl(char_code, Immediate(String::kMaxOneByteCharCode));
__ j(above, deferred->entry());
__ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
__ movq(result, FieldOperand(result,
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 0270a26..6e9e78e 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -4609,6 +4609,29 @@
j(not_equal, &next);
}
+void MacroAssembler::TestJSArrayForAllocationSiteInfo(
+ Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present) {
+ Label no_info_available;
+ ExternalReference new_space_start =
+ ExternalReference::new_space_start(isolate());
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+
+ lea(scratch_reg, Operand(receiver_reg,
+ JSArray::kSize + AllocationSiteInfo::kSize));
+ movq(kScratchRegister, new_space_start);
+ cmpq(scratch_reg, kScratchRegister);
+ j(less, &no_info_available);
+ cmpq(scratch_reg, ExternalOperand(new_space_allocation_top));
+ j(greater_equal, &no_info_available);
+ CompareRoot(MemOperand(scratch_reg, 0),
+ Heap::kAllocationSiteInfoMapRootIndex);
+ j(equal, allocation_info_present);
+ bind(&no_info_available);
+}
+
} } // namespace v8::internal
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 136f0f6..e615b89 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -1315,6 +1315,16 @@
void CheckEnumCache(Register null_value,
Label* call_runtime);
+ // AllocationSiteInfo support. Arrays may have an associated
+ // AllocationSiteInfo object that can be checked for in order to pretransition
+ // to another type.
+ // On entry, receiver_reg should point to the array object.
+ // scratch_reg gets clobbered.
+ // If allocation info is present, jump to allocation_info_present
+ void TestJSArrayForAllocationSiteInfo(Register receiver_reg,
+ Register scratch_reg,
+ Label* allocation_info_present);
+
private:
// Order general registers are pushed by Pushad.
// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index 827ec28..f5b5e95 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -234,7 +234,7 @@
// If input is ASCII, don't even bother calling here if the string to
// match contains a non-ASCII character.
if (mode_ == ASCII) {
- ASSERT(String::IsAscii(str.start(), str.length()));
+ ASSERT(String::IsOneByte(str.start(), str.length()));
}
#endif
int byte_length = str.length() * char_size();
@@ -393,8 +393,17 @@
__ j(not_equal, on_no_match); // Definitely not equal.
__ subb(rax, Immediate('a'));
__ cmpb(rax, Immediate('z' - 'a'));
+#ifndef ENABLE_LATIN_1
__ j(above, on_no_match); // Weren't letters anyway.
-
+#else
+ __ j(below_equal, &loop_increment); // In range 'a'-'z'.
+ // Latin-1: Check for values in range [224,254] but not 247.
+ __ subb(rax, Immediate(224 - 'a'));
+ __ cmpb(rax, Immediate(254 - 224));
+ __ j(above, on_no_match); // Weren't Latin-1 letters.
+ __ cmpb(rax, Immediate(247 - 224)); // Check for 247.
+ __ j(equal, on_no_match);
+#endif
__ bind(&loop_increment);
// Increment pointers into match and capture strings.
__ addq(r11, Immediate(1));
@@ -610,7 +619,7 @@
Label* on_bit_set) {
__ Move(rax, table);
Register index = current_character();
- if (mode_ != ASCII || kTableMask != String::kMaxAsciiCharCode) {
+ if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) {
__ movq(rbx, current_character());
__ and_(rbx, Immediate(kTableMask));
index = rbx;
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 994b5bc..82727ef 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -2772,7 +2772,7 @@
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
+ return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
}
@@ -3253,7 +3253,7 @@
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
+ return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
}