Version 3.14.2
ARM: allowed VFP3 instructions when hardfloat is enabled. (Chromium issue 152506)
Fixed instance_descriptors() and PushStackTraceAndDie regressions. (Chromium issue 151749)
Made GDBJIT interface compile again. (issue 1804)
Fixed Accessors::FunctionGetPrototype's proto chain traversal. (Chromium issue 143967)
Made sure that names of temporaries do not clash with real variables. (issue 2322)
Rejected local module declarations. (Chromium issue 150628)
Rejected uses of lexical for-loop variable on the RHS. (issue 2322)
Fixed slot recording of code target patches. (Chromium issue 152615,chromium:144230)
Changed the Android makefile to use GCC 4.6 instead of GCC 4.4.3.
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@12693 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/accessors.cc b/src/accessors.cc
index 9da6141..1bc9221 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -42,15 +42,11 @@
template <class C>
-static C* FindInPrototypeChain(Object* obj, bool* found_it) {
- ASSERT(!*found_it);
- Heap* heap = HEAP;
- while (!Is<C>(obj)) {
- if (obj == heap->null_value()) return NULL;
- obj = obj->GetPrototype();
+static C* FindInstanceOf(Object* obj) {
+ for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype()) {
+ if (Is<C>(cur)) return C::cast(cur);
}
- *found_it = true;
- return C::cast(obj);
+ return NULL;
}
@@ -81,10 +77,8 @@
MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
// Traverse the prototype chain until we reach an array.
- bool found_it = false;
- JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
- if (!found_it) return Smi::FromInt(0);
- return holder->length();
+ JSArray* holder = FindInstanceOf<JSArray>(object);
+ return holder == NULL ? Smi::FromInt(0) : holder->length();
}
@@ -448,15 +442,12 @@
MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
Heap* heap = Isolate::Current()->heap();
- bool found_it = false;
- JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return heap->undefined_value();
+ JSFunction* function = FindInstanceOf<JSFunction>(object);
+ if (function == NULL) return heap->undefined_value();
while (!function->should_have_prototype()) {
- found_it = false;
- function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
- &found_it);
+ function = FindInstanceOf<JSFunction>(function->GetPrototype());
// There has to be one because we hit the getter.
- ASSERT(found_it);
+ ASSERT(function != NULL);
}
if (!function->has_prototype()) {
@@ -477,9 +468,8 @@
Object* value,
void*) {
Heap* heap = object->GetHeap();
- bool found_it = false;
- JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return heap->undefined_value();
+ JSFunction* function = FindInstanceOf<JSFunction>(object);
+ if (function == NULL) return heap->undefined_value();
if (!function->should_have_prototype()) {
// Since we hit this accessor, object will have no prototype property.
return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
@@ -509,22 +499,20 @@
MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
- bool found_it = false;
- JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return Smi::FromInt(0);
+ JSFunction* function = FindInstanceOf<JSFunction>(object);
+ if (function == NULL) return Smi::FromInt(0);
// Check if already compiled.
- if (!function->shared()->is_compiled()) {
- // If the function isn't compiled yet, the length is not computed
- // correctly yet. Compile it now and return the right length.
- HandleScope scope;
- Handle<JSFunction> handle(function);
- if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
- return Failure::Exception();
- }
- return Smi::FromInt(handle->shared()->length());
- } else {
+ if (function->shared()->is_compiled()) {
return Smi::FromInt(function->shared()->length());
}
+ // If the function isn't compiled yet, the length is not computed correctly
+ // yet. Compile it now and return the right length.
+ HandleScope scope;
+ Handle<JSFunction> handle(function);
+ if (JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
+ return Smi::FromInt(handle->shared()->length());
+ }
+ return Failure::Exception();
}
@@ -541,10 +529,8 @@
MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
- bool found_it = false;
- JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return HEAP->undefined_value();
- return holder->shared()->name();
+ JSFunction* holder = FindInstanceOf<JSFunction>(object);
+ return holder == NULL ? HEAP->undefined_value() : holder->shared()->name();
}
@@ -589,9 +575,8 @@
MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
Isolate* isolate = Isolate::Current();
HandleScope scope(isolate);
- bool found_it = false;
- JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return isolate->heap()->undefined_value();
+ JSFunction* holder = FindInstanceOf<JSFunction>(object);
+ if (holder == NULL) return isolate->heap()->undefined_value();
Handle<JSFunction> function(holder, isolate);
if (function->shared()->native()) return isolate->heap()->null_value();
@@ -727,9 +712,8 @@
Isolate* isolate = Isolate::Current();
HandleScope scope(isolate);
AssertNoAllocation no_alloc;
- bool found_it = false;
- JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return isolate->heap()->undefined_value();
+ JSFunction* holder = FindInstanceOf<JSFunction>(object);
+ if (holder == NULL) return isolate->heap()->undefined_value();
if (holder->shared()->native()) return isolate->heap()->null_value();
Handle<JSFunction> function(holder, isolate);
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 30a8830..7a65ab2 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -110,6 +110,10 @@
if (FLAG_enable_armv7) {
supported_ |= 1u << ARMv7;
}
+
+ if (FLAG_enable_sudiv) {
+ supported_ |= 1u << SUDIV;
+ }
#else // __arm__
// Probe for additional features not already known to be available.
if (!IsSupported(VFP3) && OS::ArmCpuHasFeature(VFP3)) {
@@ -125,6 +129,10 @@
found_by_runtime_probing_ |= 1u << ARMv7;
}
+ if (!IsSupported(SUDIV) && OS::ArmCpuHasFeature(SUDIV)) {
+ found_by_runtime_probing_ |= 1u << SUDIV;
+ }
+
supported_ |= found_by_runtime_probing_;
#endif
@@ -1207,6 +1215,22 @@
}
+void Assembler::mls(Register dst, Register src1, Register src2, Register srcA,
+ Condition cond) {
+ ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
+ emit(cond | B22 | B21 | dst.code()*B16 | srcA.code()*B12 |
+ src2.code()*B8 | B7 | B4 | src1.code());
+}
+
+
+void Assembler::sdiv(Register dst, Register src1, Register src2,
+ Condition cond) {
+ ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
+ emit(cond | B26 | B25| B24 | B20 | dst.code()*B16 | 0xf * B12 |
+ src2.code()*B8 | B4 | src1.code());
+}
+
+
void Assembler::mul(Register dst, Register src1, Register src2,
SBit s, Condition cond) {
ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
@@ -1975,6 +1999,7 @@
void Assembler::vmov(const DwVfpRegister dst,
double imm,
+ const Register scratch,
const Condition cond) {
// Dd = immediate
// Instruction details available in ARM DDI 0406B, A8-640.
@@ -1989,22 +2014,22 @@
// using vldr from a constant pool.
uint32_t lo, hi;
DoubleAsTwoUInt32(imm, &lo, &hi);
+ mov(ip, Operand(lo));
- if (lo == hi) {
- // If the lo and hi parts of the double are equal, the literal is easier
- // to create. This is the case with 0.0.
- mov(ip, Operand(lo));
- vmov(dst, ip, ip);
- } else {
+ if (scratch.is(no_reg)) {
// Move the low part of the double into the lower of the corresponsing S
// registers of D register dst.
- mov(ip, Operand(lo));
vmov(dst.low(), ip, cond);
// Move the high part of the double into the higher of the corresponsing S
// registers of D register dst.
mov(ip, Operand(hi));
vmov(dst.high(), ip, cond);
+ } else {
+ // Move the low and high parts of the double to a D register in one
+ // instruction.
+ mov(scratch, Operand(hi));
+ vmov(dst, ip, scratch, cond);
}
}
}
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 7f2ce30..005c78d 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -511,6 +511,7 @@
ASSERT(initialized_);
if (f == VFP3 && !FLAG_enable_vfp3) return false;
if (f == VFP2 && !FLAG_enable_vfp2) return false;
+ if (f == SUDIV && !FLAG_enable_sudiv) return false;
return (supported_ & (1u << f)) != 0;
}
@@ -869,6 +870,12 @@
void mla(Register dst, Register src1, Register src2, Register srcA,
SBit s = LeaveCC, Condition cond = al);
+ void mls(Register dst, Register src1, Register src2, Register srcA,
+ Condition cond = al);
+
+ void sdiv(Register dst, Register src1, Register src2,
+ Condition cond = al);
+
void mul(Register dst, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al);
@@ -1053,6 +1060,7 @@
void vmov(const DwVfpRegister dst,
double imm,
+ const Register scratch = no_reg,
const Condition cond = al);
void vmov(const SwVfpRegister dst,
const SwVfpRegister src,
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 31cc5a2..8b0779b 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -826,6 +826,7 @@
Register object,
Destination destination,
DwVfpRegister double_dst,
+ DwVfpRegister double_scratch,
Register dst1,
Register dst2,
Register heap_number_map,
@@ -863,10 +864,10 @@
__ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
__ EmitVFPTruncate(kRoundToZero,
- single_scratch,
- double_dst,
scratch1,
+ double_dst,
scratch2,
+ double_scratch,
kCheckForInexactConversion);
// Jump to not_int32 if the operation did not succeed.
@@ -906,7 +907,8 @@
Register scratch1,
Register scratch2,
Register scratch3,
- DwVfpRegister double_scratch,
+ DwVfpRegister double_scratch0,
+ DwVfpRegister double_scratch1,
Label* not_int32) {
ASSERT(!dst.is(object));
ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object));
@@ -929,23 +931,20 @@
// Convert the floating point value to a 32-bit integer.
if (CpuFeatures::IsSupported(VFP2)) {
CpuFeatures::Scope scope(VFP2);
- SwVfpRegister single_scratch = double_scratch.low();
+
// Load the double value.
__ sub(scratch1, object, Operand(kHeapObjectTag));
- __ vldr(double_scratch, scratch1, HeapNumber::kValueOffset);
+ __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
__ EmitVFPTruncate(kRoundToZero,
- single_scratch,
- double_scratch,
+ dst,
+ double_scratch0,
scratch1,
- scratch2,
+ double_scratch1,
kCheckForInexactConversion);
// Jump to not_int32 if the operation did not succeed.
__ b(ne, not_int32);
- // Get the result in the destination register.
- __ vmov(dst, single_scratch);
-
} else {
// Load the double value in the destination registers.
__ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
@@ -2850,7 +2849,6 @@
Register scratch1 = r7;
Register scratch2 = r9;
DwVfpRegister double_scratch = d0;
- SwVfpRegister single_scratch = s3;
Register heap_number_result = no_reg;
Register heap_number_map = r6;
@@ -2888,6 +2886,7 @@
right,
destination,
d7,
+ d8,
r2,
r3,
heap_number_map,
@@ -2899,6 +2898,7 @@
left,
destination,
d6,
+ d8,
r4,
r5,
heap_number_map,
@@ -2934,10 +2934,10 @@
// transition.
__ EmitVFPTruncate(kRoundToZero,
- single_scratch,
- d5,
scratch1,
- scratch2);
+ d5,
+ scratch2,
+ d8);
if (result_type_ <= BinaryOpIC::INT32) {
// If the ne condition is set, result does
@@ -2946,7 +2946,6 @@
}
// Check if the result fits in a smi.
- __ vmov(scratch1, single_scratch);
__ add(scratch2, scratch1, Operand(0x40000000), SetCC);
// If not try to return a heap number.
__ b(mi, &return_heap_number);
@@ -3041,6 +3040,7 @@
scratch2,
scratch3,
d0,
+ d1,
&transition);
FloatingPointHelper::LoadNumberAsInt32(masm,
right,
@@ -3050,6 +3050,7 @@
scratch2,
scratch3,
d0,
+ d1,
&transition);
// The ECMA-262 standard specifies that, for shift operations, only the
@@ -3636,13 +3637,13 @@
Label not_plus_half;
// Test for 0.5.
- __ vmov(double_scratch, 0.5);
+ __ vmov(double_scratch, 0.5, scratch);
__ VFPCompareAndSetFlags(double_exponent, double_scratch);
__ b(ne, ¬_plus_half);
// Calculates square root of base. Check for the special case of
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
- __ vmov(double_scratch, -V8_INFINITY);
+ __ vmov(double_scratch, -V8_INFINITY, scratch);
__ VFPCompareAndSetFlags(double_base, double_scratch);
__ vneg(double_result, double_scratch, eq);
__ b(eq, &done);
@@ -3653,20 +3654,20 @@
__ jmp(&done);
__ bind(¬_plus_half);
- __ vmov(double_scratch, -0.5);
+ __ vmov(double_scratch, -0.5, scratch);
__ VFPCompareAndSetFlags(double_exponent, double_scratch);
__ b(ne, &call_runtime);
// Calculates square root of base. Check for the special case of
// Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
- __ vmov(double_scratch, -V8_INFINITY);
+ __ vmov(double_scratch, -V8_INFINITY, scratch);
__ VFPCompareAndSetFlags(double_base, double_scratch);
__ vmov(double_result, kDoubleRegZero, eq);
__ b(eq, &done);
// Add +0 to convert -0 to +0.
__ vadd(double_scratch, double_base, kDoubleRegZero);
- __ vmov(double_result, 1.0);
+ __ vmov(double_result, 1.0, scratch);
__ vsqrt(double_scratch, double_scratch);
__ vdiv(double_result, double_result, double_scratch);
__ jmp(&done);
@@ -3701,7 +3702,7 @@
__ mov(exponent, scratch);
}
__ vmov(double_scratch, double_base); // Back up base.
- __ vmov(double_result, 1.0);
+ __ vmov(double_result, 1.0, scratch2);
// Get absolute value of exponent.
__ cmp(scratch, Operand(0));
@@ -3717,7 +3718,7 @@
__ cmp(exponent, Operand(0));
__ b(ge, &done);
- __ vmov(double_scratch, 1.0);
+ __ vmov(double_scratch, 1.0, scratch);
__ vdiv(double_result, double_scratch, double_result);
// Test whether result is zero. Bail out to check for subnormal result.
// Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
@@ -7262,6 +7263,7 @@
#undef REG
+
bool RecordWriteStub::IsPregenerated() {
for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
!entry->object.is(no_reg);
@@ -7303,6 +7305,11 @@
}
+bool CodeStub::CanUseFPRegisters() {
+ return CpuFeatures::IsSupported(VFP2);
+}
+
+
// Takes the input in 3 registers: address_ value_ and object_. A pointer to
// the value has just been written into the object, now this stub makes sure
// we keep the GC informed. The word in the object where the value has been
@@ -7431,6 +7438,16 @@
Label need_incremental;
Label need_incremental_pop_scratch;
+ __ and_(regs_.scratch0(), regs_.object(), Operand(~Page::kPageAlignmentMask));
+ __ ldr(regs_.scratch1(),
+ MemOperand(regs_.scratch0(),
+ MemoryChunk::kWriteBarrierCounterOffset));
+ __ sub(regs_.scratch1(), regs_.scratch1(), Operand(1), SetCC);
+ __ str(regs_.scratch1(),
+ MemOperand(regs_.scratch0(),
+ MemoryChunk::kWriteBarrierCounterOffset));
+ __ b(mi, &need_incremental);
+
// Let's look at the color of the object: If it is not black we don't have
// to inform the incremental marker.
__ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
@@ -7551,7 +7568,9 @@
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
__ bind(&double_elements);
__ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
- __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r2,
+ __ StoreNumberToDoubleElements(r0, r3, r1,
+ // Overwrites all regs after this.
+ r5, r6, r7, r9, r2,
&slow_elements);
__ Ret();
}
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 3ddc405..3e79624 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -773,6 +773,7 @@
Register object,
Destination destination,
DwVfpRegister double_dst,
+ DwVfpRegister double_scratch,
Register dst1,
Register dst2,
Register heap_number_map,
@@ -794,7 +795,8 @@
Register scratch1,
Register scratch2,
Register scratch3,
- DwVfpRegister double_scratch,
+ DwVfpRegister double_scratch0,
+ DwVfpRegister double_scratch1,
Label* not_int32);
// Generate non VFP3 code to check if a double can be exactly represented by a
diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc
index 96a7d3c..7c5f63e 100644
--- a/src/arm/disasm-arm.cc
+++ b/src/arm/disasm-arm.cc
@@ -692,11 +692,19 @@
// Rn field to encode it.
Format(instr, "mul'cond's 'rn, 'rm, 'rs");
} else {
- // The MLA instruction description (A 4.1.28) refers to the order
- // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
- // Rn field to encode the Rd register and the Rd field to encode
- // the Rn register.
- Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
+ if (instr->Bit(22) == 0) {
+ // The MLA instruction description (A 4.1.28) refers to the order
+ // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
+ // Rn field to encode the Rd register and the Rd field to encode
+ // the Rn register.
+ Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
+ } else {
+ // The MLS instruction description (A 4.1.29) refers to the order
+ // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
+ // Rn field to encode the Rd register and the Rd field to encode
+ // the Rn register.
+ Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
+ }
}
} else {
// The signed/long multiply instructions use the terms RdHi and RdLo
@@ -974,6 +982,17 @@
break;
}
case db_x: {
+ if (FLAG_enable_sudiv) {
+ if (!instr->HasW()) {
+ if (instr->Bits(5, 4) == 0x1) {
+ if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
+ // SDIV (in V8 notation matching ARM ISA format) rn = rm/rs
+ Format(instr, "sdiv'cond'b 'rn, 'rm, 'rs");
+ break;
+ }
+ }
+ }
+ }
Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
break;
}
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index de09516..8ff3e93 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -2183,43 +2183,16 @@
ASSERT(prop != NULL);
ASSERT(prop->key()->AsLiteral() != NULL);
- // If the assignment starts a block of assignments to the same object,
- // change to slow case to avoid the quadratic behavior of repeatedly
- // adding fast properties.
- if (expr->starts_initialization_block()) {
- __ push(result_register());
- __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value.
- __ push(ip);
- __ CallRuntime(Runtime::kToSlowProperties, 1);
- __ pop(result_register());
- }
-
// Record source code position before IC call.
SetSourcePosition(expr->position());
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
- // Load receiver to r1. Leave a copy in the stack if needed for turning the
- // receiver into fast case.
- if (expr->ends_initialization_block()) {
- __ ldr(r1, MemOperand(sp));
- } else {
- __ pop(r1);
- }
+ __ pop(r1);
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
- // If the assignment ends an initialization block, revert to fast case.
- if (expr->ends_initialization_block()) {
- __ push(r0); // Result of assignment, saved even if not needed.
- // Receiver is under the result value.
- __ ldr(ip, MemOperand(sp, kPointerSize));
- __ push(ip);
- __ CallRuntime(Runtime::kToFastProperties, 1);
- __ pop(r0);
- __ Drop(1);
- }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(r0);
}
@@ -2228,44 +2201,16 @@
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
// Assignment to a property, using a keyed store IC.
- // If the assignment starts a block of assignments to the same object,
- // change to slow case to avoid the quadratic behavior of repeatedly
- // adding fast properties.
- if (expr->starts_initialization_block()) {
- __ push(result_register());
- // Receiver is now under the key and value.
- __ ldr(ip, MemOperand(sp, 2 * kPointerSize));
- __ push(ip);
- __ CallRuntime(Runtime::kToSlowProperties, 1);
- __ pop(result_register());
- }
-
// Record source code position before IC call.
SetSourcePosition(expr->position());
__ pop(r1); // Key.
- // Load receiver to r2. Leave a copy in the stack if needed for turning the
- // receiver into fast case.
- if (expr->ends_initialization_block()) {
- __ ldr(r2, MemOperand(sp));
- } else {
- __ pop(r2);
- }
+ __ pop(r2);
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
- // If the assignment ends an initialization block, revert to fast case.
- if (expr->ends_initialization_block()) {
- __ push(r0); // Result of assignment, saved even if not needed.
- // Receiver is under the result value.
- __ ldr(ip, MemOperand(sp, kPointerSize));
- __ push(ip);
- __ CallRuntime(Runtime::kToFastProperties, 1);
- __ pop(r0);
- __ Drop(1);
- }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(r0);
}
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 404f3c6..87d09c0 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1301,6 +1301,144 @@
}
+static void KeyedStoreGenerateGenericHelper(
+ MacroAssembler* masm,
+ Label* fast_object,
+ Label* fast_double,
+ Label* slow,
+ KeyedStoreCheckMap check_map,
+ KeyedStoreIncrementLength increment_length,
+ Register value,
+ Register key,
+ Register receiver,
+ Register receiver_map,
+ Register elements_map,
+ Register elements) {
+ Label transition_smi_elements;
+ Label finish_object_store, non_double_value, transition_double_elements;
+ Label fast_double_without_map_check;
+
+ // Fast case: Do the store, could be either Object or double.
+ __ bind(fast_object);
+ Register scratch_value = r4;
+ Register address = r5;
+ if (check_map == kCheckMap) {
+ __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
+ __ cmp(elements_map,
+ Operand(masm->isolate()->factory()->fixed_array_map()));
+ __ b(ne, fast_double);
+ }
+ // Smi stores don't require further checks.
+ Label non_smi_value;
+ __ JumpIfNotSmi(value, &non_smi_value);
+
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ add(scratch_value, key, Operand(Smi::FromInt(1)));
+ __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
+ }
+ // It's irrelevant whether array is smi-only or not when writing a smi.
+ __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
+ __ str(value, MemOperand(address));
+ __ Ret();
+
+ __ bind(&non_smi_value);
+ // Escape to elements kind transition case.
+ __ CheckFastObjectElements(receiver_map, scratch_value,
+ &transition_smi_elements);
+
+ // Fast elements array, store the value to the elements backing store.
+ __ bind(&finish_object_store);
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ add(scratch_value, key, Operand(Smi::FromInt(1)));
+ __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
+ }
+ __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
+ __ str(value, MemOperand(address));
+ // Update write barrier for the elements array address.
+ __ mov(scratch_value, value); // Preserve the value which is returned.
+ __ RecordWrite(elements,
+ address,
+ scratch_value,
+ kLRHasNotBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ __ Ret();
+
+ __ bind(fast_double);
+ if (check_map == kCheckMap) {
+ // Check for fast double array case. If this fails, call through to the
+ // runtime.
+ __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex);
+ __ b(ne, slow);
+ }
+ __ bind(&fast_double_without_map_check);
+ __ StoreNumberToDoubleElements(value,
+ key,
+ receiver,
+ elements, // Overwritten.
+ r3, // Scratch regs...
+ r4,
+ r5,
+ r6,
+ &transition_double_elements);
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ add(scratch_value, key, Operand(Smi::FromInt(1)));
+ __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
+ }
+ __ Ret();
+
+ __ bind(&transition_smi_elements);
+ // Transition the array appropriately depending on the value type.
+ __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset));
+ __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
+ __ b(ne, &non_double_value);
+
+ // Value is a double. Transition FAST_SMI_ELEMENTS ->
+ // FAST_DOUBLE_ELEMENTS and complete the store.
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
+ receiver_map,
+ r4,
+ slow);
+ ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow);
+ __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+ __ jmp(&fast_double_without_map_check);
+
+ __ bind(&non_double_value);
+ // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_ELEMENTS,
+ receiver_map,
+ r4,
+ slow);
+ ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
+ ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
+ __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+
+ __ bind(&transition_double_elements);
+ // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+ // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+ FAST_ELEMENTS,
+ receiver_map,
+ r4,
+ slow);
+ ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow);
+ __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+}
+
+
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ---------- S t a t e --------------
@@ -1309,11 +1447,9 @@
// -- r2 : receiver
// -- lr : return address
// -----------------------------------
- Label slow, array, extra, check_if_double_array;
- Label fast_object_with_map_check, fast_object_without_map_check;
- Label fast_double_with_map_check, fast_double_without_map_check;
- Label transition_smi_elements, finish_object_store, non_double_value;
- Label transition_double_elements;
+ Label slow, fast_object, fast_object_grow;
+ Label fast_double, fast_double_grow;
+ Label array, extra, check_if_double_array;
// Register usage.
Register value = r0;
@@ -1348,7 +1484,7 @@
// Check array bounds. Both the key and the length of FixedArray are smis.
__ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
__ cmp(key, Operand(ip));
- __ b(lo, &fast_object_with_map_check);
+ __ b(lo, &fast_object);
// Slow case, handle jump to runtime.
__ bind(&slow);
@@ -1373,21 +1509,13 @@
__ cmp(elements_map,
Operand(masm->isolate()->factory()->fixed_array_map()));
__ b(ne, &check_if_double_array);
- // Calculate key + 1 as smi.
- STATIC_ASSERT(kSmiTag == 0);
- __ add(r4, key, Operand(Smi::FromInt(1)));
- __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ b(&fast_object_without_map_check);
+ __ jmp(&fast_object_grow);
__ bind(&check_if_double_array);
__ cmp(elements_map,
Operand(masm->isolate()->factory()->fixed_double_array_map()));
__ b(ne, &slow);
- // Add 1 to key, and go to common element store code for doubles.
- STATIC_ASSERT(kSmiTag == 0);
- __ add(r4, key, Operand(Smi::FromInt(1)));
- __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ jmp(&fast_double_without_map_check);
+ __ jmp(&fast_double_grow);
// Array case: Get the length and the elements array from the JS
// array. Check that the array is in fast mode (and writable); if it
@@ -1399,106 +1527,15 @@
__ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ cmp(key, Operand(ip));
__ b(hs, &extra);
- // Fall through to fast case.
- __ bind(&fast_object_with_map_check);
- Register scratch_value = r4;
- Register address = r5;
- __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ cmp(elements_map,
- Operand(masm->isolate()->factory()->fixed_array_map()));
- __ b(ne, &fast_double_with_map_check);
- __ bind(&fast_object_without_map_check);
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
- __ str(value, MemOperand(address));
- __ Ret();
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ CheckFastObjectElements(receiver_map, scratch_value,
- &transition_smi_elements);
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
- __ str(value, MemOperand(address));
- // Update write barrier for the elements array address.
- __ mov(scratch_value, value); // Preserve the value which is returned.
- __ RecordWrite(elements,
- address,
- scratch_value,
- kLRHasNotBeenSaved,
- kDontSaveFPRegs,
- EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- __ Ret();
-
- __ bind(&fast_double_with_map_check);
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ cmp(elements_map,
- Operand(masm->isolate()->factory()->fixed_double_array_map()));
- __ b(ne, &slow);
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value,
- key,
- receiver,
- elements,
- r3,
- r4,
- r5,
- r6,
- &transition_double_elements);
- __ Ret();
-
- __ bind(&transition_smi_elements);
- // Transition the array appropriately depending on the value type.
- __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset));
- __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
- __ b(ne, &non_double_value);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS,
- receiver_map,
- r4,
- &slow);
- ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_ELEMENTS,
- receiver_map,
- r4,
- &slow);
- ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
- FAST_ELEMENTS,
- receiver_map,
- r4,
- &slow);
- ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
+ KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
+ &slow, kCheckMap, kDontIncrementLength,
+ value, key, receiver, receiver_map,
+ elements_map, elements);
+ KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
+ &slow, kDontCheckMap, kIncrementLength,
+ value, key, receiver, receiver_map,
+ elements_map, elements);
}
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index c71ce5d..e1ba048 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -194,22 +194,22 @@
void LBranch::PrintDataTo(StringStream* stream) {
stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
}
void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
- InputAt(0)->PrintTo(stream);
+ left()->PrintTo(stream);
stream->Add(" %s ", Token::String(op()));
- InputAt(1)->PrintTo(stream);
+ right()->PrintTo(stream);
stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}
void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(kind() == kStrictEquality ? " === " : " == ");
stream->Add(nil() == kNullValue ? "null" : "undefined");
stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
@@ -218,57 +218,57 @@
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_object(");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_string(");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_smi(");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_undetectable(");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if string_compare(");
- InputAt(0)->PrintTo(stream);
- InputAt(1)->PrintTo(stream);
+ left()->PrintTo(stream);
+ right()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_instance_type(");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_cached_array_index(");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if class_of_test(");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(", \"%o\") then B%d else B%d",
*hydrogen()->class_name(),
true_block_id(),
@@ -278,7 +278,7 @@
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if typeof ");
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
stream->Add(" == \"%s\" then B%d else B%d",
*hydrogen()->type_literal()->ToCString(),
true_block_id(), false_block_id());
@@ -292,26 +292,26 @@
void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
stream->Add("/%s ", hydrogen()->OpName());
- InputAt(0)->PrintTo(stream);
+ value()->PrintTo(stream);
}
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
- InputAt(0)->PrintTo(stream);
+ context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
}
void LStoreContextSlot::PrintDataTo(StringStream* stream) {
- InputAt(0)->PrintTo(stream);
+ context()->PrintTo(stream);
stream->Add("[%d] <- ", slot_index());
- InputAt(1)->PrintTo(stream);
+ value()->PrintTo(stream);
}
void LInvokeFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
- InputAt(0)->PrintTo(stream);
+ function()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
@@ -340,17 +340,15 @@
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
- InputAt(0)->PrintTo(stream);
+ constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream);
-
stream->Add(" length ");
length()->PrintTo(stream);
-
stream->Add(" index ");
index()->PrintTo(stream);
}
@@ -1042,7 +1040,8 @@
return DefineFixedDouble(result, d2);
} else {
LOperand* input = UseRegisterAtStart(instr->value());
- LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
+
+ LOperand* temp = (op == kMathRound) ? FixedTemp(d3) : NULL;
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
switch (op) {
case kMathAbs:
@@ -1618,8 +1617,7 @@
LOperand* temp1 = TempRegister();
LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
: NULL;
- LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d11)
- : NULL;
+ LOperand* temp3 = FixedTemp(d11);
res = DefineSameAsFirst(new(zone()) LTaggedToI(value,
temp1,
temp2,
@@ -2127,6 +2125,7 @@
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
+ ASSERT(argument_count_ == 0);
allocator_->MarkAsOsrEntry();
current_block_->last_environment()->set_ast_id(instr->ast_id());
return AssignEnvironment(new(zone()) LOsrEntry);
@@ -2266,7 +2265,7 @@
HEnvironment* env = current_block_->last_environment();
- if (instr->arguments_pushed()) {
+ if (env->entry()->arguments_pushed()) {
int argument_count = env->arguments_environment()->parameter_count();
pop = new(zone()) LDrop(argument_count);
argument_count_ -= argument_count;
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index e6e102f..5e1c991 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -261,9 +261,6 @@
virtual bool HasResult() const = 0;
virtual LOperand* result() = 0;
- virtual int TempCount() = 0;
- virtual LOperand* TempAt(int i) = 0;
-
LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; }
@@ -277,6 +274,10 @@
virtual int InputCount() = 0;
virtual LOperand* InputAt(int i) = 0;
+ friend class TempIterator;
+ virtual int TempCount() = 0;
+ virtual LOperand* TempAt(int i) = 0;
+
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
HValue* hydrogen_value_;
@@ -296,11 +297,6 @@
void set_result(LOperand* operand) { results_[0] = operand; }
LOperand* result() { return results_[0]; }
- LOperand* InputAt(int i) { return inputs_[i]; }
-
- int TempCount() { return T; }
- LOperand* TempAt(int i) { return temps_[i]; }
-
protected:
EmbeddedContainer<LOperand*, R> results_;
EmbeddedContainer<LOperand*, I> inputs_;
@@ -308,6 +304,10 @@
private:
virtual int InputCount() { return I; }
+ virtual LOperand* InputAt(int i) { return inputs_[i]; }
+
+ virtual int TempCount() { return T; }
+ virtual LOperand* TempAt(int i) { return temps_[i]; }
};
@@ -525,6 +525,8 @@
inputs_[0] = elements;
}
+ LOperand* elements() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length")
};
@@ -551,16 +553,22 @@
// Used for the standard case.
LModI(LOperand* left,
LOperand* right,
- LOperand* temp1,
+ LOperand* temp,
LOperand* temp2,
LOperand* temp3) {
inputs_[0] = left;
inputs_[1] = right;
- temps_[0] = temp1;
+ temps_[0] = temp;
temps_[1] = temp2;
temps_[2] = temp3;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+ LOperand* temp() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+ LOperand* temp3() { return temps_[2]; }
+
DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
};
@@ -573,6 +581,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
};
@@ -588,6 +599,10 @@
temps_[0] = temp;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
};
@@ -601,6 +616,10 @@
temps_[0] = temp;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
DECLARE_HYDROGEN_ACCESSOR(Mul)
};
@@ -613,6 +632,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch)
@@ -632,6 +654,9 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
@@ -647,6 +672,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch,
"cmp-object-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareObjectEqAndBranch)
@@ -659,6 +687,8 @@
inputs_[0] = left;
}
+ LOperand* left() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
"cmp-constant-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEqAndBranch)
@@ -671,6 +701,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch)
@@ -688,6 +720,9 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
@@ -702,6 +737,9 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
@@ -715,6 +753,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
@@ -729,6 +769,9 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
"is-undetectable-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
@@ -744,6 +787,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
"string-compare-and-branch")
DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
@@ -760,6 +806,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
"has-instance-type-and-branch")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
@@ -774,6 +822,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex, "get-cached-array-index")
DECLARE_HYDROGEN_ACCESSOR(GetCachedArrayIndex)
};
@@ -785,6 +835,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
"has-cached-array-index-and-branch")
DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
@@ -800,6 +852,9 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
"class-of-test-and-branch")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
@@ -815,6 +870,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
@@ -829,6 +887,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
};
@@ -840,6 +901,9 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal,
"instance-of-known-global")
DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal)
@@ -879,6 +943,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
Token::Value op() const { return hydrogen()->op(); }
DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i")
@@ -895,7 +962,8 @@
}
Token::Value op() const { return op_; }
-
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
bool can_deopt() const { return can_deopt_; }
DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i")
@@ -913,6 +981,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i")
DECLARE_HYDROGEN_ACCESSOR(Sub)
};
@@ -951,6 +1022,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
DECLARE_HYDROGEN_ACCESSOR(Branch)
@@ -965,6 +1038,9 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareMap)
@@ -986,6 +1062,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length")
DECLARE_HYDROGEN_ACCESSOR(JSArrayLength)
};
@@ -997,6 +1075,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
"fixed-array-base-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
@@ -1009,6 +1089,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(MapEnumLength, "map-enum-length")
};
@@ -1019,6 +1101,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind")
DECLARE_HYDROGEN_ACCESSOR(ElementsKind)
};
@@ -1031,6 +1115,9 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of")
DECLARE_HYDROGEN_ACCESSOR(ValueOf)
};
@@ -1043,40 +1130,26 @@
temps_[0] = temp;
}
+ LOperand* date() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+ Smi* index() const { return index_; }
+
DECLARE_CONCRETE_INSTRUCTION(ValueOf, "date-field")
DECLARE_HYDROGEN_ACCESSOR(ValueOf)
- Smi* index() const { return index_; }
private:
Smi* index_;
};
-class LSetDateField: public LTemplateInstruction<1, 2, 1> {
- public:
- LSetDateField(LOperand* date, LOperand* value, LOperand* temp, int index)
- : index_(index) {
- inputs_[0] = date;
- inputs_[1] = value;
- temps_[0] = temp;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(DateField, "date-set-field")
- DECLARE_HYDROGEN_ACCESSOR(DateField)
-
- int index() const { return index_; }
-
- private:
- int index_;
-};
-
-
class LThrow: public LTemplateInstruction<0, 1, 0> {
public:
explicit LThrow(LOperand* value) {
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
};
@@ -1087,6 +1160,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i")
};
@@ -1098,6 +1173,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i")
DECLARE_HYDROGEN_ACCESSOR(Add)
};
@@ -1110,6 +1188,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
};
@@ -1122,6 +1203,9 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(Power, "power")
DECLARE_HYDROGEN_ACCESSOR(Power)
};
@@ -1133,6 +1217,8 @@
inputs_[0] = global_object;
}
+ LOperand* global_object() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(Random, "random")
DECLARE_HYDROGEN_ACCESSOR(Random)
};
@@ -1147,6 +1233,8 @@
}
Token::Value op() const { return op_; }
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
virtual Opcode opcode() const { return LInstruction::kArithmeticD; }
virtual void CompileToNative(LCodeGen* generator);
@@ -1165,12 +1253,14 @@
inputs_[1] = right;
}
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+ Token::Value op() const { return op_; }
+
virtual Opcode opcode() const { return LInstruction::kArithmeticT; }
virtual void CompileToNative(LCodeGen* generator);
virtual const char* Mnemonic() const;
- Token::Value op() const { return op_; }
-
private:
Token::Value op_;
};
@@ -1182,6 +1272,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(Return, "return")
};
@@ -1192,6 +1284,8 @@
inputs_[0] = object;
}
+ LOperand* object() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
};
@@ -1203,10 +1297,10 @@
inputs_[0] = object;
}
+ LOperand* object() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic)
-
- LOperand* object() { return inputs_[0]; }
};
@@ -1216,10 +1310,11 @@
inputs_[0] = object;
}
+ LOperand* object() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric)
- LOperand* object() { return inputs_[0]; }
Handle<Object> name() const { return hydrogen()->name(); }
};
@@ -1230,10 +1325,10 @@
inputs_[0] = function;
}
+ LOperand* function() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype")
DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype)
-
- LOperand* function() { return inputs_[0]; }
};
@@ -1243,6 +1338,8 @@
inputs_[0] = object;
}
+ LOperand* object() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements")
};
@@ -1253,6 +1350,8 @@
inputs_[0] = object;
}
+ LOperand* object() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer,
"load-external-array-pointer")
};
@@ -1265,11 +1364,12 @@
inputs_[1] = key;
}
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement)
- LOperand* elements() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1281,12 +1381,13 @@
inputs_[1] = key;
}
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
"load-keyed-fast-double-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
- LOperand* elements() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1298,12 +1399,13 @@
inputs_[1] = key;
}
+ LOperand* external_pointer() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
"load-keyed-specialized-array-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
- LOperand* external_pointer() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
@@ -1313,15 +1415,15 @@
class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadKeyedGeneric(LOperand* obj, LOperand* key) {
- inputs_[0] = obj;
+ LLoadKeyedGeneric(LOperand* object, LOperand* key) {
+ inputs_[0] = object;
inputs_[1] = key;
}
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
-
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
};
@@ -1338,10 +1440,11 @@
inputs_[0] = global_object;
}
+ LOperand* global_object() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric)
- LOperand* global_object() { return inputs_[0]; }
Handle<Object> name() const { return hydrogen()->name(); }
bool for_typeof() const { return hydrogen()->for_typeof(); }
};
@@ -1354,10 +1457,11 @@
temps_[0] = temp;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell, "store-global-cell")
DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell)
-
- LOperand* value() { return inputs_[0]; }
};
@@ -1369,12 +1473,13 @@
inputs_[1] = value;
}
+ LOperand* global_object() { return inputs_[0]; }
+ LOperand* value() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric)
- LOperand* global_object() { return InputAt(0); }
Handle<Object> name() const { return hydrogen()->name(); }
- LOperand* value() { return InputAt(1); }
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
};
@@ -1385,10 +1490,11 @@
inputs_[0] = context;
}
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot")
DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot)
- LOperand* context() { return InputAt(0); }
int slot_index() { return hydrogen()->slot_index(); }
virtual void PrintDataTo(StringStream* stream);
@@ -1402,11 +1508,12 @@
inputs_[1] = value;
}
+ LOperand* context() { return inputs_[0]; }
+ LOperand* value() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot")
DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot)
- LOperand* context() { return InputAt(0); }
- LOperand* value() { return InputAt(1); }
int slot_index() { return hydrogen()->slot_index(); }
virtual void PrintDataTo(StringStream* stream);
@@ -1419,6 +1526,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument")
};
@@ -1455,9 +1564,9 @@
inputs_[0] = context;
}
- DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context")
+ LOperand* context() { return inputs_[0]; }
- LOperand* context() { return InputAt(0); }
+ DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context")
};
@@ -1476,7 +1585,7 @@
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
- LOperand* context() { return InputAt(0); }
+ LOperand* context() { return inputs_[0]; }
};
@@ -1486,9 +1595,9 @@
inputs_[0] = global_object;
}
- DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver")
+ LOperand* global_object() { return inputs_[0]; }
- LOperand* global() { return InputAt(0); }
+ DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver")
};
@@ -1510,11 +1619,11 @@
inputs_[0] = function;
}
+ LOperand* function() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
- LOperand* function() { return inputs_[0]; }
-
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
@@ -1528,6 +1637,8 @@
inputs_[0] = key;
}
+ LOperand* key() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed")
DECLARE_HYDROGEN_ACCESSOR(CallKeyed)
@@ -1556,10 +1667,11 @@
inputs_[0] = function;
}
+ LOperand* function() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
- LOperand* function() { return inputs_[0]; }
int arity() const { return hydrogen()->argument_count() - 1; }
};
@@ -1594,6 +1706,8 @@
inputs_[0] = constructor;
}
+ LOperand* constructor() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
@@ -1619,6 +1733,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double")
};
@@ -1629,6 +1745,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double")
};
@@ -1639,6 +1757,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i")
};
@@ -1649,18 +1769,24 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u")
};
class LNumberTagD: public LTemplateInstruction<1, 1, 2> {
public:
- LNumberTagD(LOperand* value, LOperand* temp1, LOperand* temp2) {
+ LNumberTagD(LOperand* value, LOperand* temp, LOperand* temp2) {
inputs_[0] = value;
- temps_[0] = temp1;
+ temps_[0] = temp;
temps_[1] = temp2;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d")
};
@@ -1668,12 +1794,16 @@
// Sometimes truncating conversion from a tagged value to an int32.
class LDoubleToI: public LTemplateInstruction<1, 1, 2> {
public:
- LDoubleToI(LOperand* value, LOperand* temp1, LOperand* temp2) {
+ LDoubleToI(LOperand* value, LOperand* temp, LOperand* temp2) {
inputs_[0] = value;
- temps_[0] = temp1;
+ temps_[0] = temp;
temps_[1] = temp2;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i")
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
@@ -1685,15 +1815,20 @@
class LTaggedToI: public LTemplateInstruction<1, 1, 3> {
public:
LTaggedToI(LOperand* value,
- LOperand* temp1,
+ LOperand* temp,
LOperand* temp2,
LOperand* temp3) {
inputs_[0] = value;
- temps_[0] = temp1;
+ temps_[0] = temp;
temps_[1] = temp2;
temps_[2] = temp3;
}
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+ LOperand* temp3() { return temps_[2]; }
+
DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i")
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
@@ -1707,6 +1842,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag")
};
@@ -1717,6 +1854,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change)
};
@@ -1729,10 +1868,11 @@
inputs_[0] = value;
}
- DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag")
-
+ LOperand* value() { return inputs_[0]; }
bool needs_check() const { return needs_check_; }
+ DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag")
+
private:
bool needs_check_;
};
@@ -1740,20 +1880,21 @@
class LStoreNamedField: public LTemplateInstruction<0, 2, 1> {
public:
- LStoreNamedField(LOperand* obj, LOperand* val, LOperand* temp) {
- inputs_[0] = obj;
- inputs_[1] = val;
+ LStoreNamedField(LOperand* object, LOperand* value, LOperand* temp) {
+ inputs_[0] = object;
+ inputs_[1] = value;
temps_[0] = temp;
}
+ LOperand* object() { return inputs_[0]; }
+ LOperand* value() { return inputs_[1]; }
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
virtual void PrintDataTo(StringStream* stream);
- LOperand* object() { return inputs_[0]; }
- LOperand* value() { return inputs_[1]; }
-
Handle<Object> name() const { return hydrogen()->name(); }
bool is_in_object() { return hydrogen()->is_in_object(); }
int offset() { return hydrogen()->offset(); }
@@ -1763,18 +1904,19 @@
class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> {
public:
- LStoreNamedGeneric(LOperand* obj, LOperand* val) {
- inputs_[0] = obj;
- inputs_[1] = val;
+ LStoreNamedGeneric(LOperand* object, LOperand* value) {
+ inputs_[0] = object;
+ inputs_[1] = value;
}
+ LOperand* object() { return inputs_[0]; }
+ LOperand* value() { return inputs_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
virtual void PrintDataTo(StringStream* stream);
- LOperand* object() { return inputs_[0]; }
- LOperand* value() { return inputs_[1]; }
Handle<Object> name() const { return hydrogen()->name(); }
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
};
@@ -1782,21 +1924,22 @@
class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
public:
- LStoreKeyedFastElement(LOperand* obj, LOperand* key, LOperand* val) {
- inputs_[0] = obj;
+ LStoreKeyedFastElement(LOperand* object, LOperand* key, LOperand* value) {
+ inputs_[0] = object;
inputs_[1] = key;
- inputs_[2] = val;
+ inputs_[2] = value;
}
+ LOperand* object() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement,
"store-keyed-fast-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement)
virtual void PrintDataTo(StringStream* stream);
- LOperand* object() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
- LOperand* value() { return inputs_[2]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1805,21 +1948,22 @@
public:
LStoreKeyedFastDoubleElement(LOperand* elements,
LOperand* key,
- LOperand* val) {
+ LOperand* value) {
inputs_[0] = elements;
inputs_[1] = key;
- inputs_[2] = val;
+ inputs_[2] = value;
}
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
"store-keyed-fast-double-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
virtual void PrintDataTo(StringStream* stream);
- LOperand* elements() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
- LOperand* value() { return inputs_[2]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
@@ -1828,20 +1972,21 @@
class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
public:
- LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val) {
+ LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* value) {
inputs_[0] = obj;
inputs_[1] = key;
- inputs_[2] = val;
+ inputs_[2] = value;
}
+ LOperand* object() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
virtual void PrintDataTo(StringStream* stream);
- LOperand* object() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
- LOperand* value() { return inputs_[2]; }
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
};
@@ -1849,22 +1994,21 @@
public:
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key,
- LOperand* val) {
+ LOperand* value) {
inputs_[0] = external_pointer;
inputs_[1] = key;
- inputs_[2] = val;
+ inputs_[2] = value;
}
+ LOperand* external_pointer() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
"store-keyed-specialized-array-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
- LOperand* external_pointer() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
- LOperand* value() { return inputs_[2]; }
- ElementsKind elements_kind() const {
- return hydrogen()->elements_kind();
- }
+ ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1873,21 +2017,22 @@
public:
LTransitionElementsKind(LOperand* object,
LOperand* new_map_temp,
- LOperand* temp_reg) {
+ LOperand* temp) {
inputs_[0] = object;
temps_[0] = new_map_temp;
- temps_[1] = temp_reg;
+ temps_[1] = temp;
}
+ LOperand* object() { return inputs_[0]; }
+ LOperand* new_map_temp() { return temps_[0]; }
+ LOperand* temp() { return temps_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind,
"transition-elements-kind")
DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
virtual void PrintDataTo(StringStream* stream);
- LOperand* object() { return inputs_[0]; }
- LOperand* new_map_reg() { return temps_[0]; }
- LOperand* temp_reg() { return temps_[1]; }
Handle<Map> original_map() { return hydrogen()->original_map(); }
Handle<Map> transitioned_map() { return hydrogen()->transitioned_map(); }
};
@@ -1900,11 +2045,11 @@
inputs_[1] = right;
}
- DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add")
- DECLARE_HYDROGEN_ACCESSOR(StringAdd)
-
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add")
+ DECLARE_HYDROGEN_ACCESSOR(StringAdd)
};
@@ -1916,11 +2061,11 @@
inputs_[1] = index;
}
- DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at")
- DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt)
-
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at")
+ DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt)
};
@@ -1930,10 +2075,10 @@
inputs_[0] = char_code;
}
+ LOperand* char_code() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
-
- LOperand* char_code() { return inputs_[0]; }
};
@@ -1943,10 +2088,10 @@
inputs_[0] = string;
}
+ LOperand* string() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length")
DECLARE_HYDROGEN_ACCESSOR(StringLength)
-
- LOperand* string() { return inputs_[0]; }
};
@@ -1956,7 +2101,7 @@
inputs_[0] = value;
}
- LOperand* value() { return InputAt(0); }
+ LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function")
DECLARE_HYDROGEN_ACCESSOR(CheckFunction)
@@ -1969,6 +2114,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type")
DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType)
};
@@ -1980,6 +2127,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
};
@@ -1987,11 +2136,14 @@
class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> {
public:
- LCheckPrototypeMaps(LOperand* temp1, LOperand* temp2) {
- temps_[0] = temp1;
+ LCheckPrototypeMaps(LOperand* temp, LOperand* temp2) {
+ temps_[0] = temp;
temps_[1] = temp2;
}
+ LOperand* temp() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps)
@@ -2006,6 +2158,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi")
};
@@ -2016,18 +2170,21 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
};
class LClampDToUint8: public LTemplateInstruction<1, 1, 1> {
public:
- LClampDToUint8(LOperand* value, LOperand* temp) {
- inputs_[0] = value;
+ LClampDToUint8(LOperand* unclamped, LOperand* temp) {
+ inputs_[0] = unclamped;
temps_[0] = temp;
}
LOperand* unclamped() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ClampDToUint8, "clamp-d-to-uint8")
};
@@ -2035,8 +2192,8 @@
class LClampIToUint8: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LClampIToUint8(LOperand* value) {
- inputs_[0] = value;
+ explicit LClampIToUint8(LOperand* unclamped) {
+ inputs_[0] = unclamped;
}
LOperand* unclamped() { return inputs_[0]; }
@@ -2047,12 +2204,13 @@
class LClampTToUint8: public LTemplateInstruction<1, 1, 1> {
public:
- LClampTToUint8(LOperand* value, LOperand* temp) {
- inputs_[0] = value;
+ LClampTToUint8(LOperand* unclamped, LOperand* temp) {
+ inputs_[0] = unclamped;
temps_[0] = temp;
}
LOperand* unclamped() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8, "clamp-t-to-uint8")
};
@@ -2060,11 +2218,14 @@
class LAllocateObject: public LTemplateInstruction<1, 0, 2> {
public:
- LAllocateObject(LOperand* temp1, LOperand* temp2) {
- temps_[0] = temp1;
+ LAllocateObject(LOperand* temp, LOperand* temp2) {
+ temps_[0] = temp;
temps_[1] = temp2;
}
+ LOperand* temp() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+
DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object")
DECLARE_HYDROGEN_ACCESSOR(AllocateObject)
};
@@ -2113,6 +2274,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
};
@@ -2124,6 +2287,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
};
@@ -2134,6 +2299,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch)
@@ -2149,6 +2316,8 @@
temps_[0] = temp;
}
+ LOperand* temp() { return temps_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch,
"is-construct-call-and-branch")
};
@@ -2156,15 +2325,15 @@
class LDeleteProperty: public LTemplateInstruction<1, 2, 0> {
public:
- LDeleteProperty(LOperand* obj, LOperand* key) {
- inputs_[0] = obj;
+ LDeleteProperty(LOperand* object, LOperand* key) {
+ inputs_[0] = object;
inputs_[1] = key;
}
- DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property")
-
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property")
};
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 3c7abc3..b5a0f9a 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -951,7 +951,7 @@
void LCodeGen::DoModI(LModI* instr) {
if (instr->hydrogen()->HasPowerOf2Divisor()) {
- Register dividend = ToRegister(instr->InputAt(0));
+ Register dividend = ToRegister(instr->left());
Register result = ToRegister(instr->result());
int32_t divisor =
@@ -976,112 +976,135 @@
}
// These registers hold untagged 32 bit values.
- Register left = ToRegister(instr->InputAt(0));
- Register right = ToRegister(instr->InputAt(1));
+ Register left = ToRegister(instr->left());
+ Register right = ToRegister(instr->right());
Register result = ToRegister(instr->result());
+ Label done;
- Register scratch = scratch0();
- Register scratch2 = ToRegister(instr->TempAt(0));
- DwVfpRegister dividend = ToDoubleRegister(instr->TempAt(1));
- DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2));
- DwVfpRegister quotient = double_scratch0();
+ if (CpuFeatures::IsSupported(SUDIV)) {
+ CpuFeatures::Scope scope(SUDIV);
+ // Check for x % 0.
+ if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ cmp(right, Operand(0));
+ DeoptimizeIf(eq, instr->environment());
+ }
- ASSERT(!dividend.is(divisor));
- ASSERT(!dividend.is(quotient));
- ASSERT(!divisor.is(quotient));
- ASSERT(!scratch.is(left));
- ASSERT(!scratch.is(right));
- ASSERT(!scratch.is(result));
+ // For r3 = r1 % r2; we can have the following ARM code
+ // sdiv r3, r1, r2
+ // mls r3, r3, r2, r1
- Label done, vfp_modulo, both_positive, right_negative;
+ __ sdiv(result, left, right);
+ __ mls(result, result, right, left);
+ __ cmp(result, Operand(0));
+ __ b(ne, &done);
- // Check for x % 0.
- if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ cmp(right, Operand(0));
- 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));
- __ b(eq, &done);
- // Preload right in a vfp register.
- __ vmov(divisor.low(), right);
- __ b(lt, &vfp_modulo);
-
- __ cmp(left, Operand(right));
- __ b(lt, &done);
-
- // Check for (positive) power of two on the right hand side.
- __ JumpIfNotPowerOfTwoOrZeroAndNeg(right,
- scratch,
- &right_negative,
- &both_positive);
- // Perform modulo operation (scratch contains right - 1).
- __ and_(result, scratch, Operand(left));
- __ b(&done);
-
- __ bind(&right_negative);
- // Negate right. The sign of the divisor does not matter.
- __ rsb(right, right, Operand(0));
-
- __ bind(&both_positive);
- const int kUnfolds = 3;
- // If the right hand side is smaller than the (nonnegative)
- // left hand side, the left hand side is the result.
- // Else try a few subtractions of the left hand side.
- __ mov(scratch, left);
- for (int i = 0; i < kUnfolds; i++) {
- // Check if the left hand side is less or equal than the
- // the right hand side.
- __ cmp(scratch, Operand(right));
- __ mov(result, scratch, LeaveCC, lt);
- __ b(lt, &done);
- // If not, reduce the left hand side by the right hand
- // side and check again.
- if (i < kUnfolds - 1) __ sub(scratch, scratch, right);
- }
-
- __ bind(&vfp_modulo);
- // Load the arguments in VFP registers.
- // The divisor value is preloaded before. Be careful that 'right' is only live
- // on entry.
- __ vmov(dividend.low(), left);
- // From here on don't use right as it may have been reallocated (for example
- // to scratch2).
- right = no_reg;
-
- __ vcvt_f64_s32(dividend, dividend.low());
- __ vcvt_f64_s32(divisor, divisor.low());
-
- // We do not care about the sign of the divisor.
- __ vabs(divisor, divisor);
- // Compute the quotient and round it to a 32bit integer.
- __ vdiv(quotient, dividend, divisor);
- __ vcvt_s32_f64(quotient.low(), quotient);
- __ vcvt_f64_s32(quotient, quotient.low());
-
- // Compute the remainder in result.
- DwVfpRegister double_scratch = dividend;
- __ vmul(double_scratch, divisor, quotient);
- __ vcvt_s32_f64(double_scratch.low(), double_scratch);
- __ vmov(scratch, double_scratch.low());
-
- if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- __ sub(result, left, scratch);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ cmp(left, Operand(0));
+ DeoptimizeIf(lt, instr->environment());
+ }
} else {
- Label ok;
- // Check for -0.
- __ sub(scratch2, left, scratch, SetCC);
- __ b(ne, &ok);
- __ cmp(left, Operand(0));
- DeoptimizeIf(mi, instr->environment());
- __ bind(&ok);
- // Load the result and we are done.
- __ mov(result, scratch2);
- }
+ Register scratch = scratch0();
+ Register scratch2 = ToRegister(instr->temp());
+ DwVfpRegister dividend = ToDoubleRegister(instr->temp2());
+ DwVfpRegister divisor = ToDoubleRegister(instr->temp3());
+ DwVfpRegister quotient = double_scratch0();
+ ASSERT(!dividend.is(divisor));
+ ASSERT(!dividend.is(quotient));
+ ASSERT(!divisor.is(quotient));
+ ASSERT(!scratch.is(left));
+ ASSERT(!scratch.is(right));
+ ASSERT(!scratch.is(result));
+
+ Label vfp_modulo, both_positive, right_negative;
+
+ // Check for x % 0.
+ if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ cmp(right, Operand(0));
+ 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));
+ __ b(eq, &done);
+ // Preload right in a vfp register.
+ __ vmov(divisor.low(), right);
+ __ b(lt, &vfp_modulo);
+
+ __ cmp(left, Operand(right));
+ __ b(lt, &done);
+
+ // Check for (positive) power of two on the right hand side.
+ __ JumpIfNotPowerOfTwoOrZeroAndNeg(right,
+ scratch,
+ &right_negative,
+ &both_positive);
+ // Perform modulo operation (scratch contains right - 1).
+ __ and_(result, scratch, Operand(left));
+ __ b(&done);
+
+ __ bind(&right_negative);
+ // Negate right. The sign of the divisor does not matter.
+ __ rsb(right, right, Operand(0));
+
+ __ bind(&both_positive);
+ const int kUnfolds = 3;
+ // If the right hand side is smaller than the (nonnegative)
+ // left hand side, the left hand side is the result.
+ // Else try a few subtractions of the left hand side.
+ __ mov(scratch, left);
+ for (int i = 0; i < kUnfolds; i++) {
+ // Check if the left hand side is less or equal than the
+ // the right hand side.
+ __ cmp(scratch, Operand(right));
+ __ mov(result, scratch, LeaveCC, lt);
+ __ b(lt, &done);
+ // If not, reduce the left hand side by the right hand
+ // side and check again.
+ if (i < kUnfolds - 1) __ sub(scratch, scratch, right);
+ }
+
+ __ bind(&vfp_modulo);
+ // Load the arguments in VFP registers.
+ // The divisor value is preloaded before. Be careful that 'right'
+ // is only live on entry.
+ __ vmov(dividend.low(), left);
+ // From here on don't use right as it may have been reallocated
+ // (for example to scratch2).
+ right = no_reg;
+
+ __ vcvt_f64_s32(dividend, dividend.low());
+ __ vcvt_f64_s32(divisor, divisor.low());
+
+ // We do not care about the sign of the divisor.
+ __ vabs(divisor, divisor);
+ // Compute the quotient and round it to a 32bit integer.
+ __ vdiv(quotient, dividend, divisor);
+ __ vcvt_s32_f64(quotient.low(), quotient);
+ __ vcvt_f64_s32(quotient, quotient.low());
+
+ // Compute the remainder in result.
+ DwVfpRegister double_scratch = dividend;
+ __ vmul(double_scratch, divisor, quotient);
+ __ vcvt_s32_f64(double_scratch.low(), double_scratch);
+ __ vmov(scratch, double_scratch.low());
+
+ if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ sub(result, left, scratch);
+ } else {
+ Label ok;
+ // Check for -0.
+ __ sub(scratch2, left, scratch, SetCC);
+ __ b(ne, &ok);
+ __ cmp(left, Operand(0));
+ DeoptimizeIf(mi, instr->environment());
+ __ bind(&ok);
+ // Load the result and we are done.
+ __ mov(result, scratch2);
+ }
+ }
__ bind(&done);
}
@@ -1186,15 +1209,18 @@
DeferredDivI(LCodeGen* codegen, LDivI* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
- codegen()->DoDeferredBinaryOpStub(instr_, Token::DIV);
+ codegen()->DoDeferredBinaryOpStub(instr_->pointer_map(),
+ instr_->left(),
+ instr_->right(),
+ Token::DIV);
}
virtual LInstruction* instr() { return instr_; }
private:
LDivI* instr_;
};
- const Register left = ToRegister(instr->InputAt(0));
- const Register right = ToRegister(instr->InputAt(1));
+ const Register left = ToRegister(instr->left());
+ const Register right = ToRegister(instr->right());
const Register scratch = scratch0();
const Register result = ToRegister(instr->result());
@@ -1263,15 +1289,15 @@
void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
const Register result = ToRegister(instr->result());
- const Register left = ToRegister(instr->InputAt(0));
- const Register remainder = ToRegister(instr->TempAt(0));
+ const Register left = ToRegister(instr->left());
+ const Register remainder = ToRegister(instr->temp());
const Register scratch = scratch0();
// We only optimize this for division by constants, because the standard
// integer division routine is usually slower than transitionning to VFP.
// This could be optimized on processors with SDIV available.
- ASSERT(instr->InputAt(1)->IsConstantOperand());
- int32_t divisor = ToInteger32(LConstantOperand::cast(instr->InputAt(1)));
+ ASSERT(instr->right()->IsConstantOperand());
+ int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
if (divisor < 0) {
__ cmp(left, Operand(0));
DeoptimizeIf(eq, instr->environment());
@@ -1289,11 +1315,12 @@
}
-template<int T>
-void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
+void LCodeGen::DoDeferredBinaryOpStub(LPointerMap* pointer_map,
+ LOperand* left_argument,
+ LOperand* right_argument,
Token::Value op) {
- Register left = ToRegister(instr->InputAt(0));
- Register right = ToRegister(instr->InputAt(1));
+ Register left = ToRegister(left_argument);
+ Register right = ToRegister(right_argument);
PushSafepointRegistersScope scope(this, Safepoint::kWithRegistersAndDoubles);
// Move left to r1 and right to r0 for the stub call.
@@ -1312,7 +1339,7 @@
}
BinaryOpStub stub(op, OVERWRITE_LEFT);
__ CallStub(&stub);
- RecordSafepointWithRegistersAndDoubles(instr->pointer_map(),
+ RecordSafepointWithRegistersAndDoubles(pointer_map,
0,
Safepoint::kNoLazyDeopt);
// Overwrite the stored value of r0 with the result of the stub.
@@ -1324,8 +1351,8 @@
Register scratch = scratch0();
Register result = ToRegister(instr->result());
// Note that result may alias left.
- Register left = ToRegister(instr->InputAt(0));
- LOperand* right_op = instr->InputAt(1);
+ Register left = ToRegister(instr->left());
+ LOperand* right_op = instr->right();
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
bool bailout_on_minus_zero =
@@ -1392,7 +1419,7 @@
} else {
Register right = EmitLoadRegister(right_op, scratch);
if (bailout_on_minus_zero) {
- __ orr(ToRegister(instr->TempAt(0)), left, right);
+ __ orr(ToRegister(instr->temp()), left, right);
}
if (can_overflow) {
@@ -1409,7 +1436,7 @@
Label done;
__ cmp(result, Operand(0));
__ b(ne, &done);
- __ cmp(ToRegister(instr->TempAt(0)), Operand(0));
+ __ cmp(ToRegister(instr->temp()), Operand(0));
DeoptimizeIf(mi, instr->environment());
__ bind(&done);
}
@@ -1418,8 +1445,8 @@
void LCodeGen::DoBitI(LBitI* instr) {
- LOperand* left_op = instr->InputAt(0);
- LOperand* right_op = instr->InputAt(1);
+ LOperand* left_op = instr->left();
+ LOperand* right_op = instr->right();
ASSERT(left_op->IsRegister());
Register left = ToRegister(left_op);
Register result = ToRegister(instr->result());
@@ -1452,8 +1479,8 @@
void LCodeGen::DoShiftI(LShiftI* instr) {
// Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so
// result may alias either of them.
- LOperand* right_op = instr->InputAt(1);
- Register left = ToRegister(instr->InputAt(0));
+ LOperand* right_op = instr->right();
+ Register left = ToRegister(instr->left());
Register result = ToRegister(instr->result());
Register scratch = scratch0();
if (right_op->IsRegister()) {
@@ -1517,8 +1544,8 @@
void LCodeGen::DoSubI(LSubI* instr) {
- LOperand* left = instr->InputAt(0);
- LOperand* right = instr->InputAt(1);
+ LOperand* left = instr->left();
+ LOperand* right = instr->right();
LOperand* result = instr->result();
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
SBit set_cond = can_overflow ? SetCC : LeaveCC;
@@ -1547,7 +1574,7 @@
ASSERT(instr->result()->IsDoubleRegister());
DwVfpRegister result = ToDoubleRegister(instr->result());
double v = instr->value();
- __ Vmov(result, v);
+ __ Vmov(result, v, scratch0());
}
@@ -1564,28 +1591,28 @@
void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->InputAt(0));
+ Register array = ToRegister(instr->value());
__ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
}
void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->InputAt(0));
+ Register array = ToRegister(instr->value());
__ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
}
void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
Register result = ToRegister(instr->result());
- Register map = ToRegister(instr->InputAt(0));
+ Register map = ToRegister(instr->value());
__ EnumLength(result, map);
}
void LCodeGen::DoElementsKind(LElementsKind* instr) {
Register result = ToRegister(instr->result());
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
// Load map into |result|.
__ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset));
@@ -1598,9 +1625,9 @@
void LCodeGen::DoValueOf(LValueOf* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
- Register map = ToRegister(instr->TempAt(0));
+ Register map = ToRegister(instr->temp());
Label done;
// If the object is a smi return the object.
@@ -1619,9 +1646,9 @@
void LCodeGen::DoDateField(LDateField* instr) {
- Register object = ToRegister(instr->InputAt(0));
+ Register object = ToRegister(instr->date());
Register result = ToRegister(instr->result());
- Register scratch = ToRegister(instr->TempAt(0));
+ Register scratch = ToRegister(instr->temp());
Smi* index = instr->index();
Label runtime, done;
ASSERT(object.is(result));
@@ -1658,14 +1685,14 @@
void LCodeGen::DoBitNotI(LBitNotI* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
__ mvn(result, Operand(input));
}
void LCodeGen::DoThrow(LThrow* instr) {
- Register input_reg = EmitLoadRegister(instr->InputAt(0), ip);
+ Register input_reg = EmitLoadRegister(instr->value(), ip);
__ push(input_reg);
CallRuntime(Runtime::kThrow, 1, instr);
@@ -1676,8 +1703,8 @@
void LCodeGen::DoAddI(LAddI* instr) {
- LOperand* left = instr->InputAt(0);
- LOperand* right = instr->InputAt(1);
+ LOperand* left = instr->left();
+ LOperand* right = instr->right();
LOperand* result = instr->result();
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
SBit set_cond = can_overflow ? SetCC : LeaveCC;
@@ -1697,8 +1724,8 @@
void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
- LOperand* left = instr->InputAt(0);
- LOperand* right = instr->InputAt(1);
+ LOperand* left = instr->left();
+ LOperand* right = instr->right();
HMathMinMax::Operation operation = instr->hydrogen()->operation();
Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge;
if (instr->hydrogen()->representation().IsInteger32()) {
@@ -1759,8 +1786,8 @@
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
- DoubleRegister left = ToDoubleRegister(instr->InputAt(0));
- DoubleRegister right = ToDoubleRegister(instr->InputAt(1));
+ DoubleRegister left = ToDoubleRegister(instr->left());
+ DoubleRegister right = ToDoubleRegister(instr->right());
DoubleRegister result = ToDoubleRegister(instr->result());
switch (instr->op()) {
case Token::ADD:
@@ -1799,8 +1826,8 @@
void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
- ASSERT(ToRegister(instr->InputAt(0)).is(r1));
- ASSERT(ToRegister(instr->InputAt(1)).is(r0));
+ ASSERT(ToRegister(instr->left()).is(r1));
+ ASSERT(ToRegister(instr->right()).is(r0));
ASSERT(ToRegister(instr->result()).is(r0));
BinaryOpStub stub(instr->op(), NO_OVERWRITE);
@@ -1845,11 +1872,11 @@
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32()) {
- Register reg = ToRegister(instr->InputAt(0));
+ Register reg = ToRegister(instr->value());
__ cmp(reg, Operand(0));
EmitBranch(true_block, false_block, ne);
} else if (r.IsDouble()) {
- DoubleRegister reg = ToDoubleRegister(instr->InputAt(0));
+ DoubleRegister reg = ToDoubleRegister(instr->value());
Register scratch = scratch0();
// Test the double value. Zero and NaN are false.
@@ -1858,7 +1885,7 @@
EmitBranch(true_block, false_block, eq);
} else {
ASSERT(r.IsTagged());
- Register reg = ToRegister(instr->InputAt(0));
+ Register reg = ToRegister(instr->value());
HType type = instr->hydrogen()->value()->type();
if (type.IsBoolean()) {
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
@@ -1997,8 +2024,8 @@
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
- LOperand* left = instr->InputAt(0);
- LOperand* right = instr->InputAt(1);
+ LOperand* left = instr->left();
+ LOperand* right = instr->right();
int false_block = chunk_->LookupDestination(instr->false_block_id());
int true_block = chunk_->LookupDestination(instr->true_block_id());
Condition cond = TokenToCondition(instr->op(), false);
@@ -2038,8 +2065,8 @@
void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
- Register left = ToRegister(instr->InputAt(0));
- Register right = ToRegister(instr->InputAt(1));
+ Register left = ToRegister(instr->left());
+ Register right = ToRegister(instr->right());
int false_block = chunk_->LookupDestination(instr->false_block_id());
int true_block = chunk_->LookupDestination(instr->true_block_id());
@@ -2049,7 +2076,7 @@
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
- Register left = ToRegister(instr->InputAt(0));
+ Register left = ToRegister(instr->left());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -2060,7 +2087,7 @@
void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
Register scratch = scratch0();
- Register reg = ToRegister(instr->InputAt(0));
+ Register reg = ToRegister(instr->value());
int false_block = chunk_->LookupDestination(instr->false_block_id());
// If the expression is known to be untagged or a smi, then it's definitely
@@ -2128,8 +2155,8 @@
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
- Register reg = ToRegister(instr->InputAt(0));
- Register temp1 = ToRegister(instr->TempAt(0));
+ Register reg = ToRegister(instr->value());
+ Register temp1 = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -2154,8 +2181,8 @@
void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
- Register reg = ToRegister(instr->InputAt(0));
- Register temp1 = ToRegister(instr->TempAt(0));
+ Register reg = ToRegister(instr->value());
+ Register temp1 = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -2172,15 +2199,15 @@
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
- Register input_reg = EmitLoadRegister(instr->InputAt(0), ip);
+ Register input_reg = EmitLoadRegister(instr->value(), ip);
__ tst(input_reg, Operand(kSmiTagMask));
EmitBranch(true_block, false_block, eq);
}
void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
- Register input = ToRegister(instr->InputAt(0));
- Register temp = ToRegister(instr->TempAt(0));
+ Register input = ToRegister(instr->value());
+ Register temp = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -2250,7 +2277,7 @@
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register scratch = scratch0();
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -2265,7 +2292,7 @@
void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
__ AbortIfNotString(input);
@@ -2277,7 +2304,7 @@
void LCodeGen::DoHasCachedArrayIndexAndBranch(
LHasCachedArrayIndexAndBranch* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register scratch = scratch0();
int true_block = chunk_->LookupDestination(instr->true_block_id());
@@ -2358,9 +2385,9 @@
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register temp = scratch0();
- Register temp2 = ToRegister(instr->TempAt(0));
+ Register temp2 = ToRegister(instr->temp());
Handle<String> class_name = instr->hydrogen()->class_name();
int true_block = chunk_->LookupDestination(instr->true_block_id());
@@ -2376,8 +2403,8 @@
void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
- Register reg = ToRegister(instr->InputAt(0));
- Register temp = ToRegister(instr->TempAt(0));
+ Register reg = ToRegister(instr->value());
+ Register temp = ToRegister(instr->temp());
int true_block = instr->true_block_id();
int false_block = instr->false_block_id();
@@ -2388,8 +2415,8 @@
void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
- ASSERT(ToRegister(instr->InputAt(0)).is(r0)); // Object is in r0.
- ASSERT(ToRegister(instr->InputAt(1)).is(r1)); // Function is in r1.
+ ASSERT(ToRegister(instr->left()).is(r0)); // Object is in r0.
+ ASSERT(ToRegister(instr->right()).is(r1)); // Function is in r1.
InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
@@ -2420,8 +2447,8 @@
deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
Label done, false_result;
- Register object = ToRegister(instr->InputAt(0));
- Register temp = ToRegister(instr->TempAt(0));
+ Register object = ToRegister(instr->value());
+ Register temp = ToRegister(instr->temp());
Register result = ToRegister(instr->result());
ASSERT(object.is(r0));
@@ -2501,7 +2528,7 @@
// Get the temp register reserved by the instruction. This needs to be r4 as
// its slot of the pushing of safepoint registers is used to communicate the
// offset to the location of the map check.
- Register temp = ToRegister(instr->TempAt(0));
+ Register temp = ToRegister(instr->temp());
ASSERT(temp.is(r4));
__ LoadHeapObject(InstanceofStub::right(), instr->function());
static const int kAdditionalDelta = 5;
@@ -2598,7 +2625,7 @@
// it as no longer deleted.
if (instr->hydrogen()->RequiresHoleCheck()) {
// We use a temp to check the payload (CompareRoot might clobber ip).
- Register payload = ToRegister(instr->TempAt(0));
+ Register payload = ToRegister(instr->temp());
__ ldr(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
__ CompareRoot(payload, Heap::kTheHoleValueRootIndex);
DeoptimizeIf(eq, instr->environment());
@@ -2677,7 +2704,7 @@
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
- Register object = ToRegister(instr->InputAt(0));
+ Register object = ToRegister(instr->object());
Register result = ToRegister(instr->result());
if (instr->hydrogen()->is_in_object()) {
__ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset()));
@@ -2831,7 +2858,7 @@
void LCodeGen::DoLoadElements(LLoadElements* instr) {
Register result = ToRegister(instr->result());
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->object());
Register scratch = scratch0();
__ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset));
@@ -2866,7 +2893,7 @@
void LCodeGen::DoLoadExternalArrayPointer(
LLoadExternalArrayPointer* instr) {
Register to_reg = ToRegister(instr->result());
- Register from_reg = ToRegister(instr->InputAt(0));
+ Register from_reg = ToRegister(instr->object());
__ ldr(to_reg, FieldMemOperand(from_reg,
ExternalArray::kExternalPointerOffset));
}
@@ -3123,7 +3150,7 @@
void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
- Register elem = ToRegister(instr->InputAt(0));
+ Register elem = ToRegister(instr->elements());
Register result = ToRegister(instr->result());
Label done;
@@ -3242,7 +3269,7 @@
void LCodeGen::DoPushArgument(LPushArgument* instr) {
- LOperand* argument = instr->InputAt(0);
+ LOperand* argument = instr->value();
if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) {
Abort("DoPushArgument not implemented for double type.");
} else {
@@ -3294,7 +3321,7 @@
void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
- Register global = ToRegister(instr->global());
+ Register global = ToRegister(instr->global_object());
Register result = ToRegister(instr->result());
__ ldr(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset));
}
@@ -3354,7 +3381,7 @@
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
Register scratch = scratch0();
@@ -3420,7 +3447,7 @@
void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
__ cmp(input, Operand(0));
__ Move(result, input, pl);
@@ -3450,7 +3477,7 @@
Representation r = instr->hydrogen()->value()->representation();
if (r.IsDouble()) {
- DwVfpRegister input = ToDoubleRegister(instr->InputAt(0));
+ DwVfpRegister input = ToDoubleRegister(instr->value());
DwVfpRegister result = ToDoubleRegister(instr->result());
__ vabs(result, input);
} else if (r.IsInteger32()) {
@@ -3459,7 +3486,7 @@
// Representation is tagged.
DeferredMathAbsTaggedHeapNumber* deferred =
new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
// Smi check.
__ JumpIfNotSmi(input, deferred->entry());
// If smi, handle it directly.
@@ -3470,29 +3497,24 @@
void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
- DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
+ DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
- SwVfpRegister single_scratch = double_scratch0().low();
- Register scratch1 = scratch0();
- Register scratch2 = ToRegister(instr->TempAt(0));
+ Register scratch = scratch0();
__ EmitVFPTruncate(kRoundToMinusInf,
- single_scratch,
+ result,
input,
- scratch1,
- scratch2);
+ scratch,
+ double_scratch0());
DeoptimizeIf(ne, instr->environment());
- // Move the result back to general purpose register r0.
- __ vmov(result, single_scratch);
-
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0.
Label done;
__ cmp(result, Operand(0));
__ b(ne, &done);
- __ vmov(scratch1, input.high());
- __ tst(scratch1, Operand(HeapNumber::kSignMask));
+ __ vmov(scratch, input.high());
+ __ tst(scratch, Operand(HeapNumber::kSignMask));
DeoptimizeIf(ne, instr->environment());
__ bind(&done);
}
@@ -3500,8 +3522,9 @@
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
- DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
+ DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
+ DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp());
Register scratch = scratch0();
Label done, check_sign_on_zero;
@@ -3526,12 +3549,12 @@
__ cmp(scratch, Operand(HeapNumber::kExponentBias + 32));
DeoptimizeIf(ge, instr->environment());
+ __ Vmov(double_scratch0(), 0.5, scratch);
+ __ vadd(double_scratch0(), input, double_scratch0());
+
// Save the original sign for later comparison.
__ and_(scratch, result, Operand(HeapNumber::kSignMask));
- __ Vmov(double_scratch0(), 0.5);
- __ vadd(double_scratch0(), input, double_scratch0());
-
// Check sign of the result: if the sign changed, the input
// value was in ]0.5, 0[ and the result should be -0.
__ vmov(result, double_scratch0().high());
@@ -3544,12 +3567,11 @@
}
__ EmitVFPTruncate(kRoundToMinusInf,
- double_scratch0().low(),
- double_scratch0(),
result,
- scratch);
+ double_scratch0(),
+ scratch,
+ double_scratch1);
DeoptimizeIf(ne, instr->environment());
- __ vmov(result, double_scratch0().low());
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0.
@@ -3565,22 +3587,22 @@
void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
- DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
+ DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
__ vsqrt(result, input);
}
void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
- DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
+ DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
- DoubleRegister temp = ToDoubleRegister(instr->TempAt(0));
+ DoubleRegister temp = ToDoubleRegister(instr->temp());
// Note that according to ECMA-262 15.8.2.13:
// Math.pow(-Infinity, 0.5) == Infinity
// Math.sqrt(-Infinity) == NaN
Label done;
- __ vmov(temp, -V8_INFINITY);
+ __ vmov(temp, -V8_INFINITY, scratch0());
__ VFPCompareAndSetFlags(input, temp);
__ vneg(result, temp, eq);
__ b(&done, eq);
@@ -3596,11 +3618,11 @@
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.
- ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
- ToDoubleRegister(instr->InputAt(1)).is(d2));
- ASSERT(!instr->InputAt(1)->IsRegister() ||
- ToRegister(instr->InputAt(1)).is(r2));
- ASSERT(ToDoubleRegister(instr->InputAt(0)).is(d1));
+ ASSERT(!instr->right()->IsDoubleRegister() ||
+ ToDoubleRegister(instr->right()).is(d2));
+ ASSERT(!instr->right()->IsRegister() ||
+ ToRegister(instr->right()).is(r2));
+ ASSERT(ToDoubleRegister(instr->left()).is(d1));
ASSERT(ToDoubleRegister(instr->result()).is(d3));
if (exponent_type.IsTagged()) {
@@ -3640,7 +3662,7 @@
// Having marked this instruction as a call we can use any
// registers.
ASSERT(ToDoubleRegister(instr->result()).is(d7));
- ASSERT(ToRegister(instr->InputAt(0)).is(r0));
+ ASSERT(ToRegister(instr->global_object()).is(r0));
static const int kSeedSize = sizeof(uint32_t);
STATIC_ASSERT(kPointerSize == kSeedSize);
@@ -3851,7 +3873,7 @@
void LCodeGen::DoCallNew(LCallNew* instr) {
- ASSERT(ToRegister(instr->InputAt(0)).is(r1));
+ ASSERT(ToRegister(instr->constructor()).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
@@ -3877,7 +3899,7 @@
__ mov(scratch, Operand(instr->transition()));
__ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
- Register temp = ToRegister(instr->TempAt(0));
+ Register temp = ToRegister(instr->temp());
// Update the write barrier for the map field.
__ RecordWriteField(object,
HeapObject::kMapOffset,
@@ -4062,7 +4084,7 @@
// Only load canonical NaN if the comparison above set the overflow.
__ Vmov(value,
FixedDoubleArray::canonical_not_the_hole_nan_as_double(),
- vs);
+ no_reg, vs);
}
__ vstr(value, scratch, instr->additional_index() << element_size_shift);
@@ -4155,7 +4177,7 @@
void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
Register object_reg = ToRegister(instr->object());
- Register new_map_reg = ToRegister(instr->new_map_reg());
+ Register new_map_reg = ToRegister(instr->new_map_temp());
Register scratch = scratch0();
Handle<Map> from_map = instr->original_map();
@@ -4176,7 +4198,7 @@
scratch, kLRHasBeenSaved, kDontSaveFPRegs);
} else if (IsFastSmiElementsKind(from_kind) &&
IsFastDoubleElementsKind(to_kind)) {
- Register fixed_object_reg = ToRegister(instr->temp_reg());
+ Register fixed_object_reg = ToRegister(instr->temp());
ASSERT(fixed_object_reg.is(r2));
ASSERT(new_map_reg.is(r3));
__ mov(fixed_object_reg, object_reg);
@@ -4184,7 +4206,7 @@
RelocInfo::CODE_TARGET, instr);
} else if (IsFastDoubleElementsKind(from_kind) &&
IsFastObjectElementsKind(to_kind)) {
- Register fixed_object_reg = ToRegister(instr->temp_reg());
+ Register fixed_object_reg = ToRegister(instr->temp());
ASSERT(fixed_object_reg.is(r2));
ASSERT(new_map_reg.is(r3));
__ mov(fixed_object_reg, object_reg);
@@ -4309,14 +4331,14 @@
void LCodeGen::DoStringLength(LStringLength* instr) {
- Register string = ToRegister(instr->InputAt(0));
+ Register string = ToRegister(instr->string());
Register result = ToRegister(instr->result());
__ ldr(result, FieldMemOperand(string, String::kLengthOffset));
}
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
- LOperand* input = instr->InputAt(0);
+ LOperand* input = instr->value();
ASSERT(input->IsRegister() || input->IsStackSlot());
LOperand* output = instr->result();
ASSERT(output->IsDoubleRegister());
@@ -4333,7 +4355,7 @@
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
- LOperand* input = instr->InputAt(0);
+ LOperand* input = instr->value();
LOperand* output = instr->result();
SwVfpRegister flt_scratch = double_scratch0().low();
@@ -4349,7 +4371,7 @@
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
codegen()->DoDeferredNumberTagI(instr_,
- instr_->InputAt(0),
+ instr_->value(),
SIGNED_INT32);
}
virtual LInstruction* instr() { return instr_; }
@@ -4357,7 +4379,7 @@
LNumberTagI* instr_;
};
- Register src = ToRegister(instr->InputAt(0));
+ Register src = ToRegister(instr->value());
Register dst = ToRegister(instr->result());
DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
@@ -4374,7 +4396,7 @@
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
codegen()->DoDeferredNumberTagI(instr_,
- instr_->InputAt(0),
+ instr_->value(),
UNSIGNED_INT32);
}
virtual LInstruction* instr() { return instr_; }
@@ -4382,7 +4404,7 @@
LNumberTagU* instr_;
};
- LOperand* input = instr->InputAt(0);
+ LOperand* input = instr->value();
ASSERT(input->IsRegister() && input->Equals(instr->result()));
Register reg = ToRegister(input);
@@ -4460,11 +4482,11 @@
LNumberTagD* instr_;
};
- DoubleRegister input_reg = ToDoubleRegister(instr->InputAt(0));
+ DoubleRegister input_reg = ToDoubleRegister(instr->value());
Register scratch = scratch0();
Register reg = ToRegister(instr->result());
- Register temp1 = ToRegister(instr->TempAt(0));
- Register temp2 = ToRegister(instr->TempAt(1));
+ Register temp1 = ToRegister(instr->temp());
+ Register temp2 = ToRegister(instr->temp2());
DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
if (FLAG_inline_new) {
@@ -4494,12 +4516,12 @@
void LCodeGen::DoSmiTag(LSmiTag* instr) {
ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
- __ SmiTag(ToRegister(instr->result()), ToRegister(instr->InputAt(0)));
+ __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value()));
}
void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
if (instr->needs_check()) {
STATIC_ASSERT(kHeapObjectTag == 1);
@@ -4571,11 +4593,11 @@
void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
- Register input_reg = ToRegister(instr->InputAt(0));
+ Register input_reg = ToRegister(instr->value());
Register scratch1 = scratch0();
- Register scratch2 = ToRegister(instr->TempAt(0));
+ Register scratch2 = ToRegister(instr->temp());
DwVfpRegister double_scratch = double_scratch0();
- SwVfpRegister single_scratch = double_scratch.low();
+ DwVfpRegister double_scratch2 = ToDoubleRegister(instr->temp3());
ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
@@ -4594,8 +4616,8 @@
__ cmp(scratch1, Operand(ip));
if (instr->truncating()) {
- Register scratch3 = ToRegister(instr->TempAt(1));
- DwVfpRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2));
+ Register scratch3 = ToRegister(instr->temp2());
+ SwVfpRegister single_scratch = double_scratch.low();
ASSERT(!scratch3.is(input_reg) &&
!scratch3.is(scratch1) &&
!scratch3.is(scratch2));
@@ -4630,14 +4652,12 @@
__ sub(ip, input_reg, Operand(kHeapObjectTag));
__ vldr(double_scratch, ip, HeapNumber::kValueOffset);
__ EmitVFPTruncate(kRoundToZero,
- single_scratch,
+ input_reg,
double_scratch,
scratch1,
- scratch2,
+ double_scratch2,
kCheckForInexactConversion);
DeoptimizeIf(ne, instr->environment());
- // Load the result.
- __ vmov(input_reg, single_scratch);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ cmp(input_reg, Operand(0));
@@ -4662,7 +4682,7 @@
LTaggedToI* instr_;
};
- LOperand* input = instr->InputAt(0);
+ LOperand* input = instr->value();
ASSERT(input->IsRegister());
ASSERT(input->Equals(instr->result()));
@@ -4681,7 +4701,7 @@
void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
- LOperand* input = instr->InputAt(0);
+ LOperand* input = instr->value();
ASSERT(input->IsRegister());
LOperand* result = instr->result();
ASSERT(result->IsDoubleRegister());
@@ -4699,14 +4719,14 @@
void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
Register result_reg = ToRegister(instr->result());
Register scratch1 = scratch0();
- Register scratch2 = ToRegister(instr->TempAt(0));
- DwVfpRegister double_input = ToDoubleRegister(instr->InputAt(0));
- SwVfpRegister single_scratch = double_scratch0().low();
+ Register scratch2 = ToRegister(instr->temp());
+ DwVfpRegister double_input = ToDoubleRegister(instr->value());
Label done;
if (instr->truncating()) {
- Register scratch3 = ToRegister(instr->TempAt(1));
+ Register scratch3 = ToRegister(instr->temp2());
+ SwVfpRegister single_scratch = double_scratch0().low();
__ EmitECMATruncate(result_reg,
double_input,
single_scratch,
@@ -4714,39 +4734,38 @@
scratch2,
scratch3);
} else {
- VFPRoundingMode rounding_mode = kRoundToMinusInf;
- __ EmitVFPTruncate(rounding_mode,
- single_scratch,
+ DwVfpRegister double_scratch = double_scratch0();
+ __ EmitVFPTruncate(kRoundToMinusInf,
+ result_reg,
double_input,
scratch1,
- scratch2,
+ double_scratch,
kCheckForInexactConversion);
+
// Deoptimize if we had a vfp invalid exception,
// including inexact operation.
DeoptimizeIf(ne, instr->environment());
- // Retrieve the result.
- __ vmov(result_reg, single_scratch);
}
__ bind(&done);
}
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
- LOperand* input = instr->InputAt(0);
+ LOperand* input = instr->value();
__ tst(ToRegister(input), Operand(kSmiTagMask));
DeoptimizeIf(ne, instr->environment());
}
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
- LOperand* input = instr->InputAt(0);
+ LOperand* input = instr->value();
__ tst(ToRegister(input), Operand(kSmiTagMask));
DeoptimizeIf(eq, instr->environment());
}
void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
Register scratch = scratch0();
__ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
@@ -4819,7 +4838,7 @@
void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Register scratch = scratch0();
- LOperand* input = instr->InputAt(0);
+ LOperand* input = instr->value();
ASSERT(input->IsRegister());
Register reg = ToRegister(input);
@@ -4839,7 +4858,7 @@
void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
- DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0));
+ DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
__ ClampDoubleToUint8(result_reg, value_reg, temp_reg);
}
@@ -4855,7 +4874,7 @@
Register scratch = scratch0();
Register input_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
- DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0));
+ DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
Label is_smi, done, heap_number;
// Both smi and heap number cases are handled.
@@ -4889,8 +4908,8 @@
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
- Register temp1 = ToRegister(instr->TempAt(0));
- Register temp2 = ToRegister(instr->TempAt(1));
+ Register temp1 = ToRegister(instr->temp());
+ Register temp2 = ToRegister(instr->temp2());
Handle<JSObject> holder = instr->holder();
Handle<JSObject> current_prototype = instr->prototype();
@@ -4932,8 +4951,8 @@
new(zone()) DeferredAllocateObject(this, instr);
Register result = ToRegister(instr->result());
- Register scratch = ToRegister(instr->TempAt(0));
- Register scratch2 = ToRegister(instr->TempAt(1));
+ Register scratch = ToRegister(instr->temp());
+ Register scratch2 = ToRegister(instr->temp2());
Handle<JSFunction> constructor = instr->hydrogen()->constructor();
Handle<Map> initial_map(constructor->initial_map());
int instance_size = initial_map->instance_size();
@@ -5225,7 +5244,7 @@
void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
- ASSERT(ToRegister(instr->InputAt(0)).is(r0));
+ ASSERT(ToRegister(instr->value()).is(r0));
__ push(r0);
CallRuntime(Runtime::kToFastProperties, 1, instr);
}
@@ -5306,14 +5325,14 @@
void LCodeGen::DoTypeof(LTypeof* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
__ push(input);
CallRuntime(Runtime::kTypeof, 1, instr);
}
void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
- Register input = ToRegister(instr->InputAt(0));
+ Register input = ToRegister(instr->value());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Label* true_label = chunk_->GetAssemblyLabel(true_block);
@@ -5403,7 +5422,7 @@
void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
- Register temp1 = ToRegister(instr->TempAt(0));
+ Register temp1 = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 04669b0..ac46f05 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -110,8 +110,9 @@
void FinishCode(Handle<Code> code);
// Deferred code support.
- template<int T>
- void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
+ void DoDeferredBinaryOpStub(LPointerMap* pointer_map,
+ LOperand* left_argument,
+ LOperand* right_argument,
Token::Value op);
void DoDeferredNumberTagD(LNumberTagD* instr);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index d266310..1f6ec65 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -363,12 +363,14 @@
}
-void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) {
+void MacroAssembler::Bfc(Register dst, Register src, int lsb, int width,
+ Condition cond) {
ASSERT(lsb < 32);
if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) {
int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
- bic(dst, dst, Operand(mask));
+ bic(dst, src, Operand(mask));
} else {
+ Move(dst, src, cond);
bfc(dst, lsb, width, cond);
}
}
@@ -789,6 +791,7 @@
void MacroAssembler::Vmov(const DwVfpRegister dst,
const double imm,
+ const Register scratch,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP2));
static const DoubleRepresentation minus_zero(-0.0);
@@ -800,7 +803,7 @@
} else if (value.bits == minus_zero.bits) {
vneg(dst, kDoubleRegZero, cond);
} else {
- vmov(dst, imm, cond);
+ vmov(dst, imm, scratch, cond);
}
}
@@ -1987,7 +1990,7 @@
destination = FloatingPointHelper::kCoreRegisters;
}
- Register untagged_value = receiver_reg;
+ Register untagged_value = elements_reg;
SmiUntag(untagged_value, value_reg);
FloatingPointHelper::ConvertIntToDouble(this,
untagged_value,
@@ -2436,16 +2439,27 @@
void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode,
- SwVfpRegister result,
+ Register result,
DwVfpRegister double_input,
- Register scratch1,
- Register scratch2,
+ Register scratch,
+ DwVfpRegister double_scratch,
CheckForInexactConversion check_inexact) {
+ ASSERT(!result.is(scratch));
+ ASSERT(!double_input.is(double_scratch));
+
ASSERT(CpuFeatures::IsSupported(VFP2));
CpuFeatures::Scope scope(VFP2);
- Register prev_fpscr = scratch1;
- Register scratch = scratch2;
+ Register prev_fpscr = result;
+ Label done;
+ // Test for values that can be exactly represented as a signed 32-bit integer.
+ vcvt_s32_f64(double_scratch.low(), double_input);
+ vmov(result, double_scratch.low());
+ vcvt_f64_s32(double_scratch, double_scratch.low());
+ VFPCompareAndSetFlags(double_input, double_scratch);
+ b(eq, &done);
+
+ // Convert to integer, respecting rounding mode.
int32_t check_inexact_conversion =
(check_inexact == kCheckForInexactConversion) ? kVFPInexactExceptionBit : 0;
@@ -2467,7 +2481,7 @@
vmsr(scratch);
// Convert the argument to an integer.
- vcvt_s32_f64(result,
+ vcvt_s32_f64(double_scratch.low(),
double_input,
(rounding_mode == kRoundToZero) ? kDefaultRoundToZero
: kFPSCRRounding);
@@ -2476,8 +2490,12 @@
vmrs(scratch);
// Restore FPSCR.
vmsr(prev_fpscr);
+ // Move the converted value into the result register.
+ vmov(result, double_scratch.low());
// Check for vfp exceptions.
tst(scratch, Operand(kVFPExceptionMask | check_inexact_conversion));
+
+ bind(&done);
}
@@ -3481,7 +3499,7 @@
int mask,
Condition cc,
Label* condition_met) {
- and_(scratch, object, Operand(~Page::kPageAlignmentMask));
+ Bfc(scratch, object, 0, kPageSizeBits);
ldr(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
tst(scratch, Operand(mask));
b(cc, condition_met);
@@ -3676,7 +3694,7 @@
// Double value is >= 255, return 255.
bind(&above_zero);
- Vmov(temp_double_reg, 255.0);
+ Vmov(temp_double_reg, 255.0, result_reg);
VFPCompareAndSetFlags(input_reg, temp_double_reg);
b(le, &in_bounds);
mov(result_reg, Operand(255));
@@ -3729,7 +3747,7 @@
void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
- ldr(dst, FieldMemOperand(map, Map::kBitFieldOffset));
+ ldr(dst, FieldMemOperand(map, Map::kBitField3Offset));
DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
}
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 7d127b5..c8a6a94 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -154,7 +154,7 @@
int lsb,
int width,
Condition cond = al);
- void Bfc(Register dst, int lsb, int width, Condition cond = al);
+ void Bfc(Register dst, Register src, int lsb, int width, Condition cond = al);
void Usat(Register dst, int satpos, const Operand& src,
Condition cond = al);
@@ -483,6 +483,7 @@
void Vmov(const DwVfpRegister dst,
const double imm,
+ const Register scratch = no_reg,
const Condition cond = al);
// Enter exit frame.
@@ -815,6 +816,7 @@
void StoreNumberToDoubleElements(Register value_reg,
Register key_reg,
Register receiver_reg,
+ // All regs below here overwritten.
Register elements_reg,
Register scratch1,
Register scratch2,
@@ -937,21 +939,22 @@
DwVfpRegister double_scratch,
Label *not_int32);
- // Truncates a double using a specific rounding mode.
+ // Truncates a double using a specific rounding mode, and writes the value
+ // to the result register.
// Clears the z flag (ne condition) if an overflow occurs.
- // If exact_conversion is true, the z flag is also cleared if the conversion
- // was inexact, i.e. if the double value could not be converted exactly
- // to a 32bit integer.
+ // If kCheckForInexactConversion is passed, the z flag is also cleared if the
+ // conversion was inexact, i.e. if the double value could not be converted
+ // exactly to a 32-bit integer.
void EmitVFPTruncate(VFPRoundingMode rounding_mode,
- SwVfpRegister result,
+ Register result,
DwVfpRegister double_input,
- Register scratch1,
- Register scratch2,
+ Register scratch,
+ DwVfpRegister double_scratch,
CheckForInexactConversion check
= kDontCheckForInexactConversion);
// Helper for EmitECMATruncate.
- // This will truncate a floating-point value outside of the singed 32bit
+ // This will truncate a floating-point value outside of the signed 32bit
// integer range to a 32bit signed integer.
// Expects the double value loaded in input_high and input_low.
// Exits with the answer in 'result'.
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index a057de5..91df404 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -1986,11 +1986,23 @@
SetNZFlags(alu_out);
}
} else {
- // The MLA instruction description (A 4.1.28) refers to the order
- // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
- // Rn field to encode the Rd register and the Rd field to encode
- // the Rn register.
- Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
+ int rd = instr->RdValue();
+ int32_t acc_value = get_register(rd);
+ if (instr->Bit(22) == 0) {
+ // The MLA instruction description (A 4.1.28) refers to the order
+ // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
+ // Rn field to encode the Rd register and the Rd field to encode
+ // the Rn register.
+ // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
+ int32_t mul_out = rm_val * rs_val;
+ int32_t result = acc_value + mul_out;
+ set_register(rn, result);
+ } else {
+ // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
+ int32_t mul_out = rm_val * rs_val;
+ int32_t result = acc_value - mul_out;
+ set_register(rn, result);
+ }
}
} else {
// The signed/long multiply instructions use the terms RdHi and RdLo
@@ -2546,6 +2558,25 @@
break;
}
case db_x: {
+ if (FLAG_enable_sudiv) {
+ if (!instr->HasW()) {
+ if (instr->Bits(5, 4) == 0x1) {
+ if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
+ // sdiv (in V8 notation matching ARM ISA format) rn = rm/rs
+ // Format(instr, "'sdiv'cond'b 'rn, 'rm, 'rs);
+ int rm = instr->RmValue();
+ int32_t rm_val = get_register(rm);
+ int rs = instr->RsValue();
+ int32_t rs_val = get_register(rs);
+ int32_t ret_val = 0;
+ ASSERT(rs_val != 0);
+ ret_val = rm_val/rs_val;
+ set_register(rn, ret_val);
+ return;
+ }
+ }
+ }
+ }
// Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
addr = rn_val - shifter_operand;
if (instr->HasW()) {
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 66714f8..5937e39 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -3646,6 +3646,7 @@
Register scratch0,
Register scratch1,
DwVfpRegister double_scratch0,
+ DwVfpRegister double_scratch1,
Label* fail) {
if (CpuFeatures::IsSupported(VFP2)) {
CpuFeatures::Scope scope(VFP2);
@@ -3662,13 +3663,12 @@
__ sub(ip, key, Operand(kHeapObjectTag));
__ vldr(double_scratch0, ip, HeapNumber::kValueOffset);
__ EmitVFPTruncate(kRoundToZero,
- double_scratch0.low(),
- double_scratch0,
scratch0,
+ double_scratch0,
scratch1,
+ double_scratch1,
kCheckForInexactConversion);
__ b(ne, fail);
- __ vmov(scratch0, double_scratch0.low());
__ TrySmiTag(scratch0, fail, scratch1);
__ mov(key, scratch0);
__ bind(&key_ok);
@@ -3696,7 +3696,7 @@
// 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, r4, r5, d1, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key, r4, r5, d1, d2, &miss_force_generic);
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// r3: elements array
@@ -4030,7 +4030,7 @@
// 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, r4, r5, d1, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key, r4, r5, d1, d2, &miss_force_generic);
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
@@ -4365,7 +4365,7 @@
// 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, r0, r4, r5, d1, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, r0, r4, r5, d1, d2, &miss_force_generic);
// Get the elements array.
__ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
@@ -4417,7 +4417,7 @@
// 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, r4, r5, d1, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, d2, &miss_force_generic);
// Get the elements array.
__ ldr(elements_reg,
@@ -4493,7 +4493,7 @@
// 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, r4, r5, d1, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, d2, &miss_force_generic);
if (IsFastSmiElementsKind(elements_kind)) {
__ JumpIfNotSmi(value_reg, &transition_elements_kind);
@@ -4661,7 +4661,7 @@
// 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, r4, r5, d1, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, d2, &miss_force_generic);
__ ldr(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
@@ -4686,6 +4686,7 @@
__ StoreNumberToDoubleElements(value_reg,
key_reg,
receiver_reg,
+ // All registers after this are overwritten.
elements_reg,
scratch1,
scratch2,
diff --git a/src/ast.cc b/src/ast.cc
index 6b68705..52990b8 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -126,8 +126,6 @@
pos_(pos),
binary_operation_(NULL),
assignment_id_(GetNextId(isolate)),
- block_start_(false),
- block_end_(false),
is_monomorphic_(false) { }
diff --git a/src/ast.h b/src/ast.h
index e72296c..802ac65 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1870,15 +1870,6 @@
// This check relies on the definition order of token in token.h.
bool is_compound() const { return op() > Token::ASSIGN; }
- // An initialization block is a series of statments of the form
- // x.y.z.a = ...; x.y.z.b = ...; etc. The parser marks the beginning and
- // ending of these blocks to allow for optimizations of initialization
- // blocks.
- bool starts_initialization_block() { return block_start_; }
- bool ends_initialization_block() { return block_end_; }
- void mark_block_start() { block_start_ = true; }
- void mark_block_end() { block_end_ = true; }
-
BailoutId AssignmentId() const { return assignment_id_; }
// Type feedback information.
@@ -1911,9 +1902,6 @@
BinaryOperation* binary_operation_;
const BailoutId assignment_id_;
- bool block_start_;
- bool block_end_;
-
bool is_monomorphic_;
SmallMapList receiver_types_;
};
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 9de1058..9fb79e7 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -384,7 +384,7 @@
void Genesis::SetFunctionInstanceDescriptor(
Handle<Map> map, PrototypePropertyMode prototypeMode) {
int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
- Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(size));
+ Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(0, size));
DescriptorArray::WhitenessWitness witness(*descriptors);
Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength));
@@ -525,7 +525,7 @@
void Genesis::SetStrictFunctionInstanceDescriptor(
Handle<Map> map, PrototypePropertyMode prototypeMode) {
int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
- Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(size));
+ Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(0, size));
DescriptorArray::WhitenessWitness witness(*descriptors);
Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength));
@@ -868,7 +868,8 @@
array_function->shared()->set_length(1);
Handle<Map> initial_map(array_function->initial_map());
- Handle<DescriptorArray> array_descriptors(factory->NewDescriptorArray(1));
+ Handle<DescriptorArray> array_descriptors(
+ factory->NewDescriptorArray(0, 1));
DescriptorArray::WhitenessWitness witness(*array_descriptors);
Handle<Foreign> array_length(factory->NewForeign(&Accessors::ArrayLength));
@@ -915,7 +916,8 @@
Handle<Map> string_map =
Handle<Map>(native_context()->string_function()->initial_map());
- Handle<DescriptorArray> string_descriptors(factory->NewDescriptorArray(1));
+ Handle<DescriptorArray> string_descriptors(
+ factory->NewDescriptorArray(0, 1));
DescriptorArray::WhitenessWitness witness(*string_descriptors);
Handle<Foreign> string_length(
@@ -956,7 +958,7 @@
PropertyAttributes final =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(5);
+ Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 5);
DescriptorArray::WhitenessWitness witness(*descriptors);
Map::SetDescriptors(initial_map, descriptors);
@@ -1140,7 +1142,7 @@
Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE,
Heap::kArgumentsObjectSizeStrict);
// Create the descriptor array for the arguments object.
- Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(3);
+ Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 3);
DescriptorArray::WhitenessWitness witness(*descriptors);
Map::SetDescriptors(map, descriptors);
@@ -1487,7 +1489,7 @@
Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
Handle<DescriptorArray> script_descriptors(
- factory()->NewDescriptorArray(13));
+ factory()->NewDescriptorArray(0, 13));
DescriptorArray::WhitenessWitness witness(*script_descriptors);
Handle<Foreign> script_source(
@@ -1665,7 +1667,8 @@
// Make "length" magic on instances.
Handle<Map> initial_map(array_function->initial_map());
- Handle<DescriptorArray> array_descriptors(factory()->NewDescriptorArray(1));
+ Handle<DescriptorArray> array_descriptors(
+ factory()->NewDescriptorArray(0, 1));
DescriptorArray::WhitenessWitness witness(*array_descriptors);
Handle<Foreign> array_length(factory()->NewForeign(
@@ -1765,7 +1768,7 @@
// Update map with length accessor from Array and add "index" and "input".
Handle<DescriptorArray> reresult_descriptors =
- factory()->NewDescriptorArray(3);
+ factory()->NewDescriptorArray(0, 3);
DescriptorArray::WhitenessWitness witness(*reresult_descriptors);
Map::SetDescriptors(initial_map, reresult_descriptors);
diff --git a/src/builtins.cc b/src/builtins.cc
index ffaaf8b..df70cd4 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1620,7 +1620,7 @@
// For now we generate builtin adaptor code into a stack-allocated
// buffer, before copying it into individual code objects. Be careful
// with alignment, some platforms don't like unaligned code.
- union { int force_alignment; byte buffer[4*KB]; } u;
+ union { int force_alignment; byte buffer[8*KB]; } u;
// Traverse the list of builtins and generate an adaptor in a
// separate code object for each one.
diff --git a/src/code-stubs.h b/src/code-stubs.h
index f190632..a843841 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -162,6 +162,9 @@
// Lookup the code in the (possibly custom) cache.
bool FindCodeInCache(Code** code_out);
+ protected:
+ static bool CanUseFPRegisters();
+
private:
// Nonvirtual wrapper around the stub-specific Generate function. Call
// this function to set up the macro assembler and generate the code.
@@ -998,13 +1001,15 @@
KeyedAccessGrowMode grow_mode)
: is_js_array_(is_js_array),
elements_kind_(elements_kind),
- grow_mode_(grow_mode) { }
+ grow_mode_(grow_mode),
+ fp_registers_(CanUseFPRegisters()) { }
Major MajorKey() { return KeyedStoreElement; }
int MinorKey() {
return ElementsKindBits::encode(elements_kind_) |
IsJSArrayBits::encode(is_js_array_) |
- GrowModeBits::encode(grow_mode_);
+ GrowModeBits::encode(grow_mode_) |
+ FPRegisters::encode(fp_registers_);
}
void Generate(MacroAssembler* masm);
@@ -1013,10 +1018,12 @@
class ElementsKindBits: public BitField<ElementsKind, 0, 8> {};
class GrowModeBits: public BitField<KeyedAccessGrowMode, 8, 1> {};
class IsJSArrayBits: public BitField<bool, 9, 1> {};
+ class FPRegisters: public BitField<bool, 10, 1> {};
bool is_js_array_;
ElementsKind elements_kind_;
KeyedAccessGrowMode grow_mode_;
+ bool fp_registers_;
DISALLOW_COPY_AND_ASSIGN(KeyedStoreElementStub);
};
@@ -1132,14 +1139,19 @@
class StoreArrayLiteralElementStub : public CodeStub {
public:
- explicit StoreArrayLiteralElementStub() {}
+ StoreArrayLiteralElementStub()
+ : fp_registers_(CanUseFPRegisters()) { }
private:
+ class FPRegisters: public BitField<bool, 0, 1> {};
+
Major MajorKey() { return StoreArrayLiteralElement; }
- int MinorKey() { return 0; }
+ int MinorKey() { return FPRegisters::encode(fp_registers_); }
void Generate(MacroAssembler* masm);
+ bool fp_registers_;
+
DISALLOW_COPY_AND_ASSIGN(StoreArrayLiteralElementStub);
};
diff --git a/src/cpu-profiler-inl.h b/src/cpu-profiler-inl.h
index 4982197..1133b20 100644
--- a/src/cpu-profiler-inl.h
+++ b/src/cpu-profiler-inl.h
@@ -31,7 +31,6 @@
#include "cpu-profiler.h"
#include <new>
-#include "circular-queue-inl.h"
#include "profile-generator-inl.h"
#include "unbound-queue-inl.h"
@@ -56,11 +55,18 @@
}
-TickSample* ProfilerEventsProcessor::TickSampleEvent() {
+TickSample* ProfilerEventsProcessor::StartTickSampleEvent() {
+ if (!ticks_buffer_is_empty_ || ticks_buffer_is_initialized_) return NULL;
+ ticks_buffer_is_initialized_ = true;
generator_->Tick();
- TickSampleEventRecord* evt =
- new(ticks_buffer_.Enqueue()) TickSampleEventRecord(enqueue_order_);
- return &evt->sample;
+ ticks_buffer_ = TickSampleEventRecord(enqueue_order_);
+ return &ticks_buffer_.sample;
+}
+
+
+void ProfilerEventsProcessor::FinishTickSampleEvent() {
+ ASSERT(ticks_buffer_is_initialized_ && ticks_buffer_is_empty_);
+ ticks_buffer_is_empty_ = false;
}
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 3cbac77..8f72c17 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -39,19 +39,19 @@
namespace v8 {
namespace internal {
-static const int kEventsBufferSize = 256 * KB;
-static const int kTickSamplesBufferChunkSize = 64 * KB;
-static const int kTickSamplesBufferChunksCount = 16;
static const int kProfilerStackSize = 64 * KB;
-ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
+ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator,
+ Sampler* sampler,
+ int period_in_useconds)
: Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
generator_(generator),
+ sampler_(sampler),
running_(true),
- ticks_buffer_(sizeof(TickSampleEventRecord),
- kTickSamplesBufferChunkSize,
- kTickSamplesBufferChunksCount),
+ period_in_useconds_(period_in_useconds),
+ ticks_buffer_is_empty_(true),
+ ticks_buffer_is_initialized_(false),
enqueue_order_(0) {
}
@@ -215,23 +215,17 @@
generator_->RecordTickSample(record.sample);
}
- const TickSampleEventRecord* rec =
- TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
- if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty();
- // Make a local copy of tick sample record to ensure that it won't
- // be modified as we are processing it. This is possible as the
- // sampler writes w/o any sync to the queue, so if the processor
- // will get far behind, a record may be modified right under its
- // feet.
- TickSampleEventRecord record = *rec;
- if (record.order == dequeue_order) {
+ if (ticks_buffer_is_empty_) return !ticks_from_vm_buffer_.IsEmpty();
+ if (ticks_buffer_.order == dequeue_order) {
// A paranoid check to make sure that we don't get a memory overrun
// in case of frames_count having a wild value.
- if (record.sample.frames_count < 0
- || record.sample.frames_count > TickSample::kMaxFramesCount)
- record.sample.frames_count = 0;
- generator_->RecordTickSample(record.sample);
- ticks_buffer_.FinishDequeue();
+ if (ticks_buffer_.sample.frames_count < 0
+ || ticks_buffer_.sample.frames_count > TickSample::kMaxFramesCount) {
+ ticks_buffer_.sample.frames_count = 0;
+ }
+ generator_->RecordTickSample(ticks_buffer_.sample);
+ ticks_buffer_is_empty_ = true;
+ ticks_buffer_is_initialized_ = false;
} else {
return true;
}
@@ -239,22 +233,29 @@
}
+void ProfilerEventsProcessor::ProcessEventsQueue(int64_t stop_time,
+ unsigned* dequeue_order) {
+ while (OS::Ticks() < stop_time) {
+ if (ProcessTicks(*dequeue_order)) {
+ // All ticks of the current dequeue_order are processed,
+ // proceed to the next code event.
+ ProcessCodeEvent(dequeue_order);
+ }
+ }
+}
+
+
void ProfilerEventsProcessor::Run() {
unsigned dequeue_order = 0;
while (running_) {
- // Process ticks until we have any.
- if (ProcessTicks(dequeue_order)) {
- // All ticks of the current dequeue_order are processed,
- // proceed to the next code event.
- ProcessCodeEvent(&dequeue_order);
+ int64_t stop_time = OS::Ticks() + period_in_useconds_;
+ if (sampler_ != NULL) {
+ sampler_->DoSample();
}
- YieldCPU();
+ ProcessEventsQueue(stop_time, &dequeue_order);
}
- // Process remaining tick events.
- ticks_buffer_.FlushResidualRecords();
- // Perform processing until we have tick events, skip remaining code events.
while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
}
@@ -310,15 +311,22 @@
}
-TickSample* CpuProfiler::TickSampleEvent(Isolate* isolate) {
+TickSample* CpuProfiler::StartTickSampleEvent(Isolate* isolate) {
if (CpuProfiler::is_profiling(isolate)) {
- return isolate->cpu_profiler()->processor_->TickSampleEvent();
+ return isolate->cpu_profiler()->processor_->StartTickSampleEvent();
} else {
return NULL;
}
}
+void CpuProfiler::FinishTickSampleEvent(Isolate* isolate) {
+ if (CpuProfiler::is_profiling(isolate)) {
+ isolate->cpu_profiler()->processor_->FinishTickSampleEvent();
+ }
+}
+
+
void CpuProfiler::DeleteAllProfiles() {
Isolate* isolate = Isolate::Current();
ASSERT(isolate->cpu_profiler() != NULL);
@@ -486,13 +494,15 @@
if (processor_ == NULL) {
Isolate* isolate = Isolate::Current();
+ Sampler* sampler = isolate->logger()->sampler();
// Disable logging when using the new implementation.
saved_logging_nesting_ = isolate->logger()->logging_nesting_;
isolate->logger()->logging_nesting_ = 0;
generator_ = new ProfileGenerator(profiles_);
- processor_ = new ProfilerEventsProcessor(generator_);
+ processor_ = new ProfilerEventsProcessor(generator_,
+ sampler,
+ FLAG_cpu_profiler_sampling_period);
NoBarrier_Store(&is_profiling_, true);
- processor_->Start();
// Enumerate stuff we already have in the heap.
if (isolate->heap()->HasBeenSetUp()) {
if (!FLAG_prof_browser_mode) {
@@ -505,12 +515,12 @@
isolate->logger()->LogAccessorCallbacks();
}
// Enable stack sampling.
- Sampler* sampler = reinterpret_cast<Sampler*>(isolate->logger()->ticker_);
if (!sampler->IsActive()) {
sampler->Start();
need_to_stop_sampler_ = true;
}
sampler->IncreaseProfilingDepth();
+ processor_->Start();
}
}
@@ -545,16 +555,16 @@
void CpuProfiler::StopProcessor() {
+ NoBarrier_Store(&is_profiling_, false);
+ processor_->Stop();
+ processor_->Join();
Logger* logger = Isolate::Current()->logger();
- Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
+ Sampler* sampler = logger->sampler();
sampler->DecreaseProfilingDepth();
if (need_to_stop_sampler_) {
sampler->Stop();
need_to_stop_sampler_ = false;
}
- NoBarrier_Store(&is_profiling_, false);
- processor_->Stop();
- processor_->Join();
delete processor_;
delete generator_;
processor_ = NULL;
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 9cd4484..f4bc0c7 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -124,7 +124,9 @@
// methods called by event producers: VM and stack sampler threads.
class ProfilerEventsProcessor : public Thread {
public:
- explicit ProfilerEventsProcessor(ProfileGenerator* generator);
+ explicit ProfilerEventsProcessor(ProfileGenerator* generator,
+ Sampler* sampler,
+ int period_in_useconds);
virtual ~ProfilerEventsProcessor() {}
// Thread control.
@@ -156,11 +158,12 @@
// Puts current stack into tick sample events buffer.
void AddCurrentStack();
- // Tick sample events are filled directly in the buffer of the circular
- // queue (because the structure is of fixed width, but usually not all
- // stack frame entries are filled.) This method returns a pointer to the
- // next record of the buffer.
- INLINE(TickSample* TickSampleEvent());
+ // StartTickSampleEvent returns a pointer only if the ticks_buffer_ is empty,
+ // FinishTickSampleEvent marks the ticks_buffer_ as filled.
+ // Finish should be called only after successful Start (returning non-NULL
+ // pointer).
+ INLINE(TickSample* StartTickSampleEvent());
+ INLINE(void FinishTickSampleEvent());
private:
union CodeEventsContainer {
@@ -173,13 +176,19 @@
// Called from events processing thread (Run() method.)
bool ProcessCodeEvent(unsigned* dequeue_order);
bool ProcessTicks(unsigned dequeue_order);
+ void ProcessEventsQueue(int64_t stop_time, unsigned* dequeue_order);
INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
ProfileGenerator* generator_;
+ Sampler* sampler_;
bool running_;
+ // Sampling period in microseconds.
+ const int period_in_useconds_;
UnboundQueue<CodeEventsContainer> events_buffer_;
- SamplingCircularQueue ticks_buffer_;
+ TickSampleEventRecord ticks_buffer_;
+ bool ticks_buffer_is_empty_;
+ bool ticks_buffer_is_initialized_;
UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
unsigned enqueue_order_;
};
@@ -218,7 +227,10 @@
static bool HasDetachedProfiles();
// Invoked from stack sampler (thread or signal handler.)
- static TickSample* TickSampleEvent(Isolate* isolate);
+ // Finish should be called only after successful Start (returning non-NULL
+ // pointer).
+ static TickSample* StartTickSampleEvent(Isolate* isolate);
+ static void FinishTickSampleEvent(Isolate* isolate);
// Must be called via PROFILE macro, otherwise will crash when
// profiling is not enabled.
diff --git a/src/dateparser-inl.h b/src/dateparser-inl.h
index a5c7143..3cb36fa 100644
--- a/src/dateparser-inl.h
+++ b/src/dateparser-inl.h
@@ -62,7 +62,8 @@
// sss is in the range 000..999,
// hh is in the range 00..23,
// mm, ss, and sss default to 00 if missing, and
- // timezone defaults to Z if missing.
+ // timezone defaults to Z if missing
+ // (following Safari, ISO actually demands local time).
// Extensions:
// We also allow sss to have more or less than three digits (but at
// least one).
diff --git a/src/elements.cc b/src/elements.cc
index 4cb50a4..39686a2 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -1268,7 +1268,30 @@
JSArray* array,
Object* length_object,
uint32_t length) {
- if (length == 0) {
+ Heap* heap = array->GetHeap();
+ int capacity = dict->Capacity();
+ uint32_t new_length = length;
+ uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
+ if (new_length < old_length) {
+ // Find last non-deletable element in range of elements to be
+ // deleted and adjust range accordingly.
+ for (int i = 0; i < capacity; i++) {
+ Object* key = dict->KeyAt(i);
+ if (key->IsNumber()) {
+ uint32_t number = static_cast<uint32_t>(key->Number());
+ if (new_length <= number && number < old_length) {
+ PropertyDetails details = dict->DetailsAt(i);
+ if (details.IsDontDelete()) new_length = number + 1;
+ }
+ }
+ }
+ if (new_length != length) {
+ MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
+ if (!maybe_object->To(&length_object)) return maybe_object;
+ }
+ }
+
+ if (new_length == 0) {
// If the length of a slow array is reset to zero, we clear
// the array and flush backing storage. This has the added
// benefit that the array returns to fast mode.
@@ -1276,45 +1299,22 @@
MaybeObject* maybe_obj = array->ResetElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
} else {
- uint32_t new_length = length;
- uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
- if (new_length < old_length) {
- // Find last non-deletable element in range of elements to be
- // deleted and adjust range accordingly.
- Heap* heap = array->GetHeap();
- int capacity = dict->Capacity();
- for (int i = 0; i < capacity; i++) {
- Object* key = dict->KeyAt(i);
- if (key->IsNumber()) {
- uint32_t number = static_cast<uint32_t>(key->Number());
- if (new_length <= number && number < old_length) {
- PropertyDetails details = dict->DetailsAt(i);
- if (details.IsDontDelete()) new_length = number + 1;
- }
+ // Remove elements that should be deleted.
+ int removed_entries = 0;
+ Object* the_hole_value = heap->the_hole_value();
+ for (int i = 0; i < capacity; i++) {
+ Object* key = dict->KeyAt(i);
+ if (key->IsNumber()) {
+ uint32_t number = static_cast<uint32_t>(key->Number());
+ if (new_length <= number && number < old_length) {
+ dict->SetEntry(i, the_hole_value, the_hole_value);
+ removed_entries++;
}
}
- if (new_length != length) {
- MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
- if (!maybe_object->To(&length_object)) return maybe_object;
- }
-
- // Remove elements that should be deleted.
- int removed_entries = 0;
- Object* the_hole_value = heap->the_hole_value();
- for (int i = 0; i < capacity; i++) {
- Object* key = dict->KeyAt(i);
- if (key->IsNumber()) {
- uint32_t number = static_cast<uint32_t>(key->Number());
- if (new_length <= number && number < old_length) {
- dict->SetEntry(i, the_hole_value, the_hole_value);
- removed_entries++;
- }
- }
- }
-
- // Update the number of elements.
- dict->ElementsRemoved(removed_entries);
}
+
+ // Update the number of elements.
+ dict->ElementsRemoved(removed_entries);
}
return length_object;
}
diff --git a/src/factory.cc b/src/factory.cc
index 462af59..a2bb939 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -112,10 +112,11 @@
}
-Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors) {
+Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors,
+ int slack) {
ASSERT(0 <= number_of_descriptors);
CALL_HEAP_FUNCTION(isolate(),
- DescriptorArray::Allocate(number_of_descriptors),
+ DescriptorArray::Allocate(number_of_descriptors, slack),
DescriptorArray);
}
@@ -1284,10 +1285,26 @@
result->shared()->DontAdaptArguments();
// Recursively copy parent templates' accessors, 'data' may be modified.
+ int max_number_of_additional_properties = 0;
+ FunctionTemplateInfo* info = *obj;
+ while (true) {
+ Object* props = info->property_accessors();
+ if (!props->IsUndefined()) {
+ Handle<Object> props_handle(props);
+ NeanderArray props_array(props_handle);
+ max_number_of_additional_properties += props_array.length();
+ }
+ Object* parent = info->parent_template();
+ if (parent->IsUndefined()) break;
+ info = FunctionTemplateInfo::cast(parent);
+ }
+
+ Map::EnsureDescriptorSlack(map, max_number_of_additional_properties);
+
while (true) {
Handle<Object> props = Handle<Object>(obj->property_accessors());
if (!props->IsUndefined()) {
- Map::CopyAppendCallbackDescriptors(map, props);
+ Map::AppendCallbackDescriptors(map, props);
}
Handle<Object> parent = Handle<Object>(obj->parent_template());
if (parent->IsUndefined()) break;
diff --git a/src/factory.h b/src/factory.h
index e617abb..51065aa 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -66,7 +66,8 @@
Handle<ObjectHashTable> NewObjectHashTable(int at_least_space_for);
- Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
+ Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors,
+ int slack = 0);
Handle<DeoptimizationInputData> NewDeoptimizationInputData(
int deopt_entry_count,
PretenureFlag pretenure);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 685559a..81ec78a 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -284,6 +284,8 @@
"enable use of VFP2 instructions if available")
DEFINE_bool(enable_armv7, true,
"enable use of ARMv7 instructions if available (ARM only)")
+DEFINE_bool(enable_sudiv, true,
+ "enable use of SDIV and UDIV instructions if available (ARM only)")
DEFINE_bool(enable_fpu, true,
"enable use of MIPS FPU instructions if available (MIPS only)")
@@ -333,6 +335,10 @@
DEFINE_bool(cache_prototype_transitions, true, "cache prototype transitions")
+// cpu-profiler.cc
+DEFINE_int(cpu_profiler_sampling_period, 1000,
+ "CPU profiler sampling period in microseconds")
+
// debug.cc
DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
DEFINE_bool(debugger_auto_break, true,
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index d3cd447..ecf645d 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -31,11 +31,13 @@
#include "bootstrapper.h"
#include "compiler.h"
+#include "frames.h"
+#include "frames-inl.h"
#include "global-handles.h"
#include "messages.h"
-#include "platform.h"
#include "natives.h"
-#include "scopeinfo.h"
+#include "platform.h"
+#include "scopes.h"
namespace v8 {
namespace internal {
@@ -194,7 +196,7 @@
virtual void WriteBody(Writer::Slot<THeader> header, Writer* writer) {
uintptr_t start = writer->position();
- if (WriteBody(writer)) {
+ if (WriteBodyInternal(writer)) {
uintptr_t end = writer->position();
header->offset = start;
#if defined(__MACH_O)
@@ -204,7 +206,7 @@
}
}
- virtual bool WriteBody(Writer* writer) {
+ virtual bool WriteBodyInternal(Writer* writer) {
return false;
}
@@ -340,14 +342,14 @@
virtual void WriteBody(Writer::Slot<Header> header, Writer* w) {
uintptr_t start = w->position();
- if (WriteBody(w)) {
+ if (WriteBodyInternal(w)) {
uintptr_t end = w->position();
header->offset = start;
header->size = end - start;
}
}
- virtual bool WriteBody(Writer* w) {
+ virtual bool WriteBodyInternal(Writer* w) {
return false;
}
@@ -627,9 +629,9 @@
#if defined(__ELF)
class ELF BASE_EMBEDDED {
public:
- ELF() : sections_(6) {
- sections_.Add(new ELFSection("", ELFSection::TYPE_NULL, 0));
- sections_.Add(new StringTable(".shstrtab"));
+ ELF(Zone* zone) : sections_(6, zone) {
+ sections_.Add(new(zone) ELFSection("", ELFSection::TYPE_NULL, 0), zone);
+ sections_.Add(new(zone) StringTable(".shstrtab"), zone);
}
void Write(Writer* w) {
@@ -642,8 +644,8 @@
return sections_[index];
}
- uint32_t AddSection(ELFSection* section) {
- sections_.Add(section);
+ uint32_t AddSection(ELFSection* section, Zone* zone) {
+ sections_.Add(section, zone);
section->set_index(sections_.length() - 1);
return sections_.length() - 1;
}
@@ -675,7 +677,7 @@
{ 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#elif defined(V8_TARGET_ARCH_X64)
const uint8_t ident[16] =
- { 0x7f, 'E', 'L', 'F', 2, 1, 1, 0, 0, 0 , 0, 0, 0, 0, 0, 0};
+ { 0x7f, 'E', 'L', 'F', 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#else
#error Unsupported target architecture.
#endif
@@ -852,10 +854,10 @@
class ELFSymbolTable : public ELFSection {
public:
- explicit ELFSymbolTable(const char* name)
+ ELFSymbolTable(const char* name, Zone* zone)
: ELFSection(name, TYPE_SYMTAB, sizeof(uintptr_t)),
- locals_(1),
- globals_(1) {
+ locals_(1, zone),
+ globals_(1, zone) {
}
virtual void WriteBody(Writer::Slot<Header> header, Writer* w) {
@@ -883,11 +885,11 @@
strtab->DetachWriter();
}
- void Add(const ELFSymbol& symbol) {
+ void Add(const ELFSymbol& symbol, Zone* zone) {
if (symbol.binding() == ELFSymbol::BIND_LOCAL) {
- locals_.Add(symbol);
+ locals_.Add(symbol, zone);
} else {
- globals_.Add(symbol);
+ globals_.Add(symbol, zone);
}
}
@@ -1019,26 +1021,29 @@
static void CreateSymbolsTable(CodeDescription* desc,
ELF* elf,
int text_section_index) {
- ELFSymbolTable* symtab = new ELFSymbolTable(".symtab");
- StringTable* strtab = new StringTable(".strtab");
+ Zone* zone = desc->info()->zone();
+ ELFSymbolTable* symtab = new(zone) ELFSymbolTable(".symtab", zone);
+ StringTable* strtab = new(zone) StringTable(".strtab");
// Symbol table should be followed by the linked string table.
- elf->AddSection(symtab);
- elf->AddSection(strtab);
+ elf->AddSection(symtab, zone);
+ elf->AddSection(strtab, zone);
symtab->Add(ELFSymbol("V8 Code",
0,
0,
ELFSymbol::BIND_LOCAL,
ELFSymbol::TYPE_FILE,
- ELFSection::INDEX_ABSOLUTE));
+ ELFSection::INDEX_ABSOLUTE),
+ zone);
symtab->Add(ELFSymbol(desc->name(),
0,
desc->CodeSize(),
ELFSymbol::BIND_GLOBAL,
ELFSymbol::TYPE_FUNC,
- text_section_index));
+ text_section_index),
+ zone);
}
#endif // defined(__ELF)
@@ -1074,7 +1079,7 @@
DW_ATE_SIGNED = 0x5
};
- bool WriteBody(Writer* w) {
+ bool WriteBodyInternal(Writer* w) {
uintptr_t cu_start = w->position();
Writer::Slot<uint32_t> size = w->CreateSlotHere<uint32_t>();
uintptr_t start = w->position();
@@ -1094,8 +1099,7 @@
w->WriteString("v8value");
if (desc_->IsInfoAvailable()) {
- CompilationInfo* info = desc_->info();
- ScopeInfo<FreeStoreAllocationPolicy> scope_info(info->scope());
+ Scope* scope = desc_->info()->scope();
w->WriteULEB128(2);
w->WriteString(desc_->name());
w->Write<intptr_t>(desc_->CodeStart());
@@ -1106,23 +1110,25 @@
w->Write<uint8_t>(DW_OP_reg5); // The frame pointer's here on ia32
#elif defined(V8_TARGET_ARCH_X64)
w->Write<uint8_t>(DW_OP_reg6); // and here on x64.
+#elif defined(V8_TARGET_ARCH_ARM)
+ UNIMPLEMENTED();
#else
#error Unsupported target architecture.
#endif
fb_block_size.set(static_cast<uint32_t>(w->position() - fb_block_start));
- int params = scope_info.number_of_parameters();
- int slots = scope_info.number_of_stack_slots();
- int context_slots = scope_info.number_of_context_slots();
+ int params = scope->num_parameters();
+ int slots = scope->num_stack_slots();
+ int context_slots = scope->ContextLocalCount();
// The real slot ID is internal_slots + context_slot_id.
int internal_slots = Context::MIN_CONTEXT_SLOTS;
- int locals = scope_info.LocalCount();
+ int locals = scope->StackLocalCount();
int current_abbreviation = 4;
for (int param = 0; param < params; ++param) {
w->WriteULEB128(current_abbreviation++);
w->WriteString(
- *scope_info.ParameterName(param)->ToCString(DISALLOW_NULLS));
+ *scope->parameter(param)->name()->ToCString(DISALLOW_NULLS));
w->Write<uint32_t>(ty_offset);
Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
uintptr_t block_start = w->position();
@@ -1148,7 +1154,7 @@
ASSERT(Context::CLOSURE_INDEX == 0);
ASSERT(Context::PREVIOUS_INDEX == 1);
ASSERT(Context::EXTENSION_INDEX == 2);
- ASSERT(Context::GLOBAL_INDEX == 3);
+ ASSERT(Context::GLOBAL_OBJECT_INDEX == 3);
w->WriteULEB128(current_abbreviation++);
w->WriteString(".closure");
w->WriteULEB128(current_abbreviation++);
@@ -1167,10 +1173,13 @@
w->WriteString(builder.Finalize());
}
+ ZoneList<Variable*> stack_locals(locals, scope->zone());
+ ZoneList<Variable*> context_locals(context_slots, scope->zone());
+ scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
for (int local = 0; local < locals; ++local) {
w->WriteULEB128(current_abbreviation++);
w->WriteString(
- *scope_info.LocalName(local)->ToCString(DISALLOW_NULLS));
+ *stack_locals[local]->name()->ToCString(DISALLOW_NULLS));
w->Write<uint32_t>(ty_offset);
Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
uintptr_t block_start = w->position();
@@ -1287,7 +1296,7 @@
w->WriteULEB128(0);
}
- bool WriteBody(Writer* w) {
+ bool WriteBodyInternal(Writer* w) {
int current_abbreviation = 1;
bool extra_info = desc_->IsInfoAvailable();
ASSERT(desc_->IsLineInfoAvailable());
@@ -1306,14 +1315,13 @@
w->WriteULEB128(0);
if (extra_info) {
- CompilationInfo* info = desc_->info();
- ScopeInfo<FreeStoreAllocationPolicy> scope_info(info->scope());
- int params = scope_info.number_of_parameters();
- int slots = scope_info.number_of_stack_slots();
- int context_slots = scope_info.number_of_context_slots();
+ Scope* scope = desc_->info()->scope();
+ int params = scope->num_parameters();
+ int slots = scope->num_stack_slots();
+ int context_slots = scope->ContextLocalCount();
// The real slot ID is internal_slots + context_slot_id.
int internal_slots = Context::MIN_CONTEXT_SLOTS;
- int locals = scope_info.LocalCount();
+ int locals = scope->StackLocalCount();
int total_children =
params + slots + context_slots + internal_slots + locals + 2;
@@ -1418,7 +1426,7 @@
DW_LNE_DEFINE_FILE = 3
};
- bool WriteBody(Writer* w) {
+ bool WriteBodyInternal(Writer* w) {
// Write prologue.
Writer::Slot<uint32_t> total_length = w->CreateSlotHere<uint32_t>();
uintptr_t start = w->position();
@@ -1558,7 +1566,7 @@
class UnwindInfoSection : public DebugSection {
public:
explicit UnwindInfoSection(CodeDescription* desc);
- virtual bool WriteBody(Writer* w);
+ virtual bool WriteBodyInternal(Writer* w);
int WriteCIE(Writer* w);
void WriteFDE(Writer* w, int);
@@ -1770,7 +1778,7 @@
}
-bool UnwindInfoSection::WriteBody(Writer* w) {
+bool UnwindInfoSection::WriteBodyInternal(Writer* w) {
uint32_t cie_position = WriteCIE(w);
WriteFDE(w, cie_position);
return true;
@@ -1780,13 +1788,14 @@
#endif // V8_TARGET_ARCH_X64
static void CreateDWARFSections(CodeDescription* desc, DebugObject* obj) {
+ Zone* zone = desc->info()->zone();
if (desc->IsLineInfoAvailable()) {
- obj->AddSection(new DebugInfoSection(desc));
- obj->AddSection(new DebugAbbrevSection(desc));
- obj->AddSection(new DebugLineSection(desc));
+ obj->AddSection(new(zone) DebugInfoSection(desc), zone);
+ obj->AddSection(new(zone) DebugAbbrevSection(desc), zone);
+ obj->AddSection(new(zone) DebugLineSection(desc), zone);
}
#ifdef V8_TARGET_ARCH_X64
- obj->AddSection(new UnwindInfoSection(desc));
+ obj->AddSection(new(zone) UnwindInfoSection(desc), zone);
#endif
}
@@ -1905,7 +1914,8 @@
static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
- ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT);
+ Zone* zone = desc->info()->zone();
+ ZoneScope zone_scope(zone, DELETE_ON_EXIT);
#ifdef __MACH_O
MachO mach_o;
Writer w(&mach_o);
@@ -1918,17 +1928,19 @@
mach_o.Write(&w, desc->CodeStart(), desc->CodeSize());
#else
- ELF elf;
+ ELF elf(zone);
Writer w(&elf);
int text_section_index = elf.AddSection(
- new FullHeaderELFSection(".text",
- ELFSection::TYPE_NOBITS,
- kCodeAlignment,
- desc->CodeStart(),
- 0,
- desc->CodeSize(),
- ELFSection::FLAG_ALLOC | ELFSection::FLAG_EXEC));
+ new(zone) FullHeaderELFSection(
+ ".text",
+ ELFSection::TYPE_NOBITS,
+ kCodeAlignment,
+ desc->CodeStart(),
+ 0,
+ desc->CodeSize(),
+ ELFSection::FLAG_ALLOC | ELFSection::FLAG_EXEC),
+ zone);
CreateSymbolsTable(desc, &elf, text_section_index);
diff --git a/src/handles.cc b/src/handles.cc
index 7999a10..46399d6 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -735,7 +735,7 @@
}
DescriptorArray* desc = object->map()->instance_descriptors();
- Handle<FixedArray> keys(FixedArray::cast(desc->GetEnumCache()), isolate);
+ Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
// In case the number of properties required in the enum are actually
// present, we can reuse the enum cache. Otherwise, this means that the
diff --git a/src/heap.cc b/src/heap.cc
index bdb63bf..d5d1128 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -371,6 +371,12 @@
lo_space_->SizeOfObjects() / KB,
lo_space_->Available() / KB,
lo_space_->CommittedMemory() / KB);
+ PrintPID("All spaces, used: %6" V8_PTR_PREFIX "d KB"
+ ", available: %6" V8_PTR_PREFIX "d KB"
+ ", committed: %6" V8_PTR_PREFIX "d KB\n",
+ this->SizeOfObjects() / KB,
+ this->Available() / KB,
+ this->CommittedMemory() / KB);
PrintPID("Total time spent in GC : %d ms\n", total_gc_time_ms_);
}
@@ -619,10 +625,12 @@
PerformGarbageCollection(collector, &tracer);
rate->Stop();
+ ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
+
+ // This can do debug callbacks and restart incremental marking.
GarbageCollectionEpilogue();
}
- ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
if (incremental_marking()->IsStopped()) {
if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) {
incremental_marking()->Start();
@@ -4187,7 +4195,7 @@
StringDictionary* dictionary;
MaybeObject* maybe_dictionary =
StringDictionary::Allocate(
- map->NumberOfDescribedProperties() * 2 + initial_size);
+ map->NumberOfOwnDescriptors() * 2 + initial_size);
if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
// The global object might be created from an object template with accessors.
@@ -5125,7 +5133,8 @@
// The size factor is in range [5..250]. The numbers here are chosen from
// experiments. If you changes them, make sure to test with
// chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
- intptr_t step_size = size_factor * IncrementalMarking::kAllocatedThreshold;
+ intptr_t step_size =
+ size_factor * IncrementalMarking::kAllocatedThreshold;
if (contexts_disposed_ > 0) {
if (hint >= kMaxHint) {
diff --git a/src/heap.h b/src/heap.h
index 90d0797..d6a3d29 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -176,6 +176,7 @@
V(constructor_symbol, "constructor") \
V(code_symbol, ".code") \
V(result_symbol, ".result") \
+ V(dot_for_symbol, ".for.") \
V(catch_var_symbol, ".catch-var") \
V(empty_symbol, "") \
V(eval_symbol, "eval") \
@@ -1499,13 +1500,6 @@
void ClearNormalizedMapCaches();
- // Clears the cache of ICs related to this map.
- void ClearCacheOnMap(Map* map) {
- if (FLAG_cleanup_code_caches_at_gc) {
- map->ClearCodeCache(this);
- }
- }
-
GCTracer* tracer() { return tracer_; }
// Returns the size of objects residing in non new spaces.
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 0192a76..2c3f2da 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -707,7 +707,7 @@
void HCallKnownGlobal::PrintDataTo(StringStream* stream) {
- stream->Add("o ", target()->shared()->DebugName());
+ stream->Add("%o ", target()->shared()->DebugName());
stream->Add("#%d", argument_count());
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index ebc86a9..a4e9ed7 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -53,6 +53,7 @@
#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
+ V(BinaryOperation) \
V(BitwiseBinaryOperation) \
V(ControlInstruction) \
V(Instruction) \
@@ -1472,21 +1473,13 @@
class HLeaveInlined: public HTemplateInstruction<0> {
public:
- explicit HLeaveInlined(bool arguments_pushed)
- : arguments_pushed_(arguments_pushed) { }
+ HLeaveInlined() { }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
- bool arguments_pushed() {
- return arguments_pushed_;
- }
-
DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
-
- private:
- bool arguments_pushed_;
};
@@ -2685,6 +2678,8 @@
virtual bool IsCommutative() const { return false; }
virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
};
@@ -4535,6 +4530,7 @@
SetOperandAt(0, elements);
SetOperandAt(1, key);
SetOperandAt(2, val);
+ SetFlag(kDeoptimizeOnUndefined);
SetGVNFlag(kChangesDoubleArrayElements);
}
@@ -4668,10 +4664,6 @@
transitioned_map_(transitioned_map) {
SetOperandAt(0, object);
SetFlag(kUseGVN);
- // Don't set GVN DependOn flags here. That would defeat GVN's detection of
- // congruent HTransitionElementsKind instructions. Instruction hoisting
- // handles HTransitionElementsKind instruction specially, explicitly adding
- // DependsOn flags during its dependency calculations.
SetGVNFlag(kChangesElementsKind);
if (original_map->has_fast_double_elements()) {
SetGVNFlag(kChangesElementsPointer);
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index c30a88b..1afa660 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -168,10 +168,9 @@
void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) {
bool drop_extra = state != NULL &&
state->inlining_kind() == DROP_EXTRA_ON_RETURN;
- bool arguments_pushed = state != NULL && state->arguments_pushed();
if (block->IsInlineReturnTarget()) {
- AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
+ AddInstruction(new(zone()) HLeaveInlined());
last_environment_ = last_environment()->DiscardInlined(drop_extra);
}
@@ -185,11 +184,10 @@
FunctionState* state) {
HBasicBlock* target = state->function_return();
bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN;
- bool arguments_pushed = state->arguments_pushed();
ASSERT(target->IsInlineReturnTarget());
ASSERT(return_value != NULL);
- AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
+ AddInstruction(new(zone()) HLeaveInlined());
last_environment_ = last_environment()->DiscardInlined(drop_extra);
last_environment()->Push(return_value);
AddSimulate(BailoutId::None());
@@ -1950,52 +1948,6 @@
if (can_hoist && !graph()->use_optimistic_licm()) {
can_hoist = block->IsLoopSuccessorDominator();
}
- if (instr->IsTransitionElementsKind()) {
- // It's possible to hoist transitions out of a loop as long as the
- // hoisting wouldn't move the transition past an instruction that has a
- // DependsOn flag for anything it changes.
- GVNFlagSet hoist_depends_blockers =
- HValue::ConvertChangesToDependsFlags(instr->ChangesFlags());
-
- // In addition, the transition must not be hoisted above elements kind
- // changes, or if the transition is destructive to the elements buffer,
- // changes to array pointer or array contents.
- GVNFlagSet hoist_change_blockers;
- hoist_change_blockers.Add(kChangesElementsKind);
- HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr);
- if (trans->original_map()->has_fast_double_elements()) {
- hoist_change_blockers.Add(kChangesElementsPointer);
- hoist_change_blockers.Add(kChangesDoubleArrayElements);
- }
- if (trans->transitioned_map()->has_fast_double_elements()) {
- hoist_change_blockers.Add(kChangesElementsPointer);
- hoist_change_blockers.Add(kChangesArrayElements);
- }
- if (FLAG_trace_gvn) {
- GVNFlagSet hoist_blockers = hoist_depends_blockers;
- hoist_blockers.Add(hoist_change_blockers);
- GVNFlagSet first_time = *first_time_changes;
- first_time.Add(*first_time_depends);
- TRACE_GVN_4("Checking dependencies on HTransitionElementsKind "
- "%d (%s) hoist blockers: %s; "
- "first-time accumulated: %s\n",
- instr->id(),
- instr->Mnemonic(),
- *GetGVNFlagsString(hoist_blockers),
- *GetGVNFlagsString(first_time));
- }
- // It's possible to hoist transition from the current loop loop only if
- // they dominate all of the successor blocks in the same loop and there
- // are not any instructions that have Changes/DependsOn that intervene
- // between it and the beginning of the loop header.
- bool in_nested_loop = block != loop_header &&
- ((block->parent_loop_header() != loop_header) ||
- block->IsLoopHeader());
- can_hoist = !in_nested_loop &&
- block->IsLoopSuccessorDominator() &&
- !first_time_depends->ContainsAnyOf(hoist_depends_blockers) &&
- !first_time_changes->ContainsAnyOf(hoist_change_blockers);
- }
if (can_hoist) {
bool inputs_loop_invariant = true;
@@ -3615,7 +3567,10 @@
HConstant(new_offset, Representation::Integer32());
if (*add == NULL) {
new_constant->InsertBefore(check);
- *add = new(BasicBlock()->zone()) HAdd(NULL,
+ // Because of the bounds checks elimination algorithm, the index is always
+ // an HAdd or an HSub here, so we can safely cast to an HBinaryOperation.
+ HValue* context = HBinaryOperation::cast(check->index())->context();
+ *add = new(BasicBlock()->zone()) HAdd(context,
original_value,
new_constant);
(*add)->AssumeRepresentation(representation);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index ea68c50..f291b05 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -2105,6 +2105,16 @@
}
+void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) {
+ ASSERT(CpuFeatures::IsEnabled(SSE2));
+ EnsureSpace ensure_space(this);
+ EMIT(0x66);
+ EMIT(0x0F);
+ EMIT(0x76);
+ emit_sse_operand(dst, src);
+}
+
+
void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) {
ASSERT(CpuFeatures::IsEnabled(SSE2));
EnsureSpace ensure_space(this);
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index f95e7b7..4d9562e 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -1016,6 +1016,7 @@
void movmskpd(Register dst, XMMRegister src);
void cmpltsd(XMMRegister dst, XMMRegister src);
+ void pcmpeqd(XMMRegister dst, XMMRegister src);
void movaps(XMMRegister dst, XMMRegister src);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 1fdbaf1..142abb5 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -1793,9 +1793,10 @@
if (result_type_ <= BinaryOpIC::INT32) {
__ cvttsd2si(ecx, Operand(xmm0));
__ cvtsi2sd(xmm2, ecx);
- __ ucomisd(xmm0, xmm2);
- __ j(not_zero, ¬_int32);
- __ j(carry, ¬_int32);
+ __ pcmpeqd(xmm2, xmm0);
+ __ movmskpd(ecx, xmm2);
+ __ test(ecx, Immediate(1));
+ __ j(zero, ¬_int32);
}
GenerateHeapResultAllocation(masm, &call_runtime);
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
@@ -3213,7 +3214,7 @@
__ movsd(double_scratch2, double_result); // Load double_exponent with 1.
// Get absolute value of exponent.
- Label no_neg, while_true, no_multiply, while_false;
+ Label no_neg, while_true, while_false;
__ test(scratch, scratch);
__ j(positive, &no_neg, Label::kNear);
__ neg(scratch);
@@ -7205,6 +7206,11 @@
}
+bool CodeStub::CanUseFPRegisters() {
+ return CpuFeatures::IsSupported(SSE2);
+}
+
+
// Takes the input in 3 registers: address_ value_ and object_. A pointer to
// the value has just been written into the object, now this stub makes sure
// we keep the GC informed. The word in the object where the value has been
@@ -7325,6 +7331,17 @@
Mode mode) {
Label object_is_black, need_incremental, need_incremental_pop_object;
+ __ mov(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask));
+ __ and_(regs_.scratch0(), regs_.object());
+ __ mov(regs_.scratch1(),
+ Operand(regs_.scratch0(),
+ MemoryChunk::kWriteBarrierCounterOffset));
+ __ sub(regs_.scratch1(), Immediate(1));
+ __ mov(Operand(regs_.scratch0(),
+ MemoryChunk::kWriteBarrierCounterOffset),
+ regs_.scratch1());
+ __ j(negative, &need_incremental);
+
// Let's look at the color of the object: If it is not black we don't have
// to inform the incremental marker.
__ JumpIfBlack(regs_.object(),
diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
index 008fdde..75b46bd 100644
--- a/src/ia32/disasm-ia32.cc
+++ b/src/ia32/disasm-ia32.cc
@@ -1305,6 +1305,14 @@
NameOfXMMRegister(rm),
static_cast<int>(imm8));
data += 2;
+ } else if (*data == 0x76) {
+ data++;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, ®op, &rm);
+ AppendToBuffer("pcmpeqd %s,%s",
+ NameOfXMMRegister(regop),
+ NameOfXMMRegister(rm));
+ data++;
} else if (*data == 0x90) {
data++;
AppendToBuffer("nop"); // 2 byte nop.
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index a058701..72021b4 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -2139,37 +2139,15 @@
ASSERT(prop != NULL);
ASSERT(prop->key()->AsLiteral() != NULL);
- // If the assignment starts a block of assignments to the same object,
- // change to slow case to avoid the quadratic behavior of repeatedly
- // adding fast properties.
- if (expr->starts_initialization_block()) {
- __ push(result_register());
- __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
- __ CallRuntime(Runtime::kToSlowProperties, 1);
- __ pop(result_register());
- }
-
// Record source code position before IC call.
SetSourcePosition(expr->position());
__ mov(ecx, prop->key()->AsLiteral()->handle());
- if (expr->ends_initialization_block()) {
- __ mov(edx, Operand(esp, 0));
- } else {
- __ pop(edx);
- }
+ __ pop(edx);
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
- // If the assignment ends an initialization block, revert to fast case.
- if (expr->ends_initialization_block()) {
- __ push(eax); // Result of assignment, saved even if not needed.
- __ push(Operand(esp, kPointerSize)); // Receiver is under value.
- __ CallRuntime(Runtime::kToFastProperties, 1);
- __ pop(eax);
- __ Drop(1);
- }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(eax);
}
@@ -2181,23 +2159,8 @@
// esp[0] : key
// esp[kPointerSize] : receiver
- // If the assignment starts a block of assignments to the same object,
- // change to slow case to avoid the quadratic behavior of repeatedly
- // adding fast properties.
- if (expr->starts_initialization_block()) {
- __ push(result_register());
- // Receiver is now under the key and value.
- __ push(Operand(esp, 2 * kPointerSize));
- __ CallRuntime(Runtime::kToSlowProperties, 1);
- __ pop(result_register());
- }
-
__ pop(ecx); // Key.
- if (expr->ends_initialization_block()) {
- __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
- } else {
- __ pop(edx);
- }
+ __ pop(edx);
// Record source code position before IC call.
SetSourcePosition(expr->position());
Handle<Code> ic = is_classic_mode()
@@ -2205,15 +2168,6 @@
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
- // If the assignment ends an initialization block, revert to fast case.
- if (expr->ends_initialization_block()) {
- __ pop(edx);
- __ push(eax); // Result of assignment, saved even if not needed.
- __ push(edx);
- __ CallRuntime(Runtime::kToFastProperties, 1);
- __ pop(eax);
- }
-
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(eax);
}
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 52d8fa1..dae3bbd 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -747,6 +747,125 @@
}
+static void KeyedStoreGenerateGenericHelper(
+ MacroAssembler* masm,
+ Label* fast_object,
+ Label* fast_double,
+ Label* slow,
+ KeyedStoreCheckMap check_map,
+ KeyedStoreIncrementLength increment_length) {
+ Label transition_smi_elements;
+ Label finish_object_store, non_double_value, transition_double_elements;
+ Label fast_double_without_map_check;
+ // eax: value
+ // ecx: key (a smi)
+ // edx: receiver
+ // ebx: FixedArray receiver->elements
+ // edi: receiver map
+ // Fast case: Do the store, could either Object or double.
+ __ bind(fast_object);
+ if (check_map == kCheckMap) {
+ __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
+ __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
+ __ j(not_equal, fast_double);
+ }
+ // Smi stores don't require further checks.
+ Label non_smi_value;
+ __ JumpIfNotSmi(eax, &non_smi_value);
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ add(FieldOperand(edx, JSArray::kLengthOffset),
+ Immediate(Smi::FromInt(1)));
+ }
+ // It's irrelevant whether array is smi-only or not when writing a smi.
+ __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
+ __ ret(0);
+
+ __ bind(&non_smi_value);
+ // Escape to elements kind transition case.
+ __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
+ __ CheckFastObjectElements(edi, &transition_smi_elements);
+
+ // Fast elements array, store the value to the elements backing store.
+ __ bind(&finish_object_store);
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ add(FieldOperand(edx, JSArray::kLengthOffset),
+ Immediate(Smi::FromInt(1)));
+ }
+ __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
+ // Update write barrier for the elements array address.
+ __ mov(edx, eax); // Preserve the value which is returned.
+ __ RecordWriteArray(
+ ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+ __ ret(0);
+
+ __ bind(fast_double);
+ if (check_map == kCheckMap) {
+ // Check for fast double array case. If this fails, call through to the
+ // runtime.
+ __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
+ __ j(not_equal, slow);
+ // If the value is a number, store it as a double in the FastDoubleElements
+ // array.
+ }
+ __ bind(&fast_double_without_map_check);
+ __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
+ &transition_double_elements, false);
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ add(FieldOperand(edx, JSArray::kLengthOffset),
+ Immediate(Smi::FromInt(1)));
+ }
+ __ ret(0);
+
+ __ bind(&transition_smi_elements);
+ __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+
+ // Transition the array appropriately depending on the value type.
+ __ CheckMap(eax,
+ masm->isolate()->factory()->heap_number_map(),
+ &non_double_value,
+ DONT_DO_SMI_CHECK);
+
+ // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
+ // and complete the store.
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
+ ebx,
+ edi,
+ slow);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow);
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ jmp(&fast_double_without_map_check);
+
+ __ bind(&non_double_value);
+ // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_ELEMENTS,
+ ebx,
+ edi,
+ slow);
+ ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+
+ __ bind(&transition_double_elements);
+ // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+ // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+ __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+ FAST_ELEMENTS,
+ ebx,
+ edi,
+ slow);
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow);
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+}
+
+
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
@@ -755,10 +874,9 @@
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
- Label slow, fast_object_with_map_check, fast_object_without_map_check;
- Label fast_double_with_map_check, fast_double_without_map_check;
- Label check_if_double_array, array, extra, transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
+ Label slow, fast_object, fast_object_grow;
+ Label fast_double, fast_double_grow;
+ Label array, extra, check_if_double_array;
// Check that the object isn't a smi.
__ JumpIfSmi(edx, &slow);
@@ -785,7 +903,7 @@
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
// Check array bounds. Both the key and the length of FixedArray are smis.
__ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
- __ j(below, &fast_object_with_map_check);
+ __ j(below, &fast_object);
// Slow case: call runtime.
__ bind(&slow);
@@ -808,18 +926,12 @@
__ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
__ cmp(edi, masm->isolate()->factory()->fixed_array_map());
__ j(not_equal, &check_if_double_array);
- // Add 1 to receiver->length, and go to common element store code for Objects.
- __ add(FieldOperand(edx, JSArray::kLengthOffset),
- Immediate(Smi::FromInt(1)));
- __ jmp(&fast_object_without_map_check);
+ __ jmp(&fast_object_grow);
__ bind(&check_if_double_array);
__ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
__ j(not_equal, &slow);
- // Add 1 to receiver->length, and go to common element store code for doubles.
- __ add(FieldOperand(edx, JSArray::kLengthOffset),
- Immediate(Smi::FromInt(1)));
- __ jmp(&fast_double_without_map_check);
+ __ jmp(&fast_double_grow);
// Array case: Get the length and the elements array from the JS
// array. Check that the array is in fast mode (and writable); if it
@@ -836,94 +948,10 @@
__ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
__ j(above_equal, &extra);
- // Fast case: Do the store, could either Object or double.
- __ bind(&fast_object_with_map_check);
- // eax: value
- // ecx: key (a smi)
- // edx: receiver
- // ebx: FixedArray receiver->elements
- // edi: receiver map
- __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
- __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
- __ j(not_equal, &fast_double_with_map_check);
- __ bind(&fast_object_without_map_check);
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(eax, &non_smi_value);
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
- __ ret(0);
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
- __ CheckFastObjectElements(edi, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
- // Update write barrier for the elements array address.
- __ mov(edx, eax); // Preserve the value which is returned.
- __ RecordWriteArray(
- ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ ret(0);
-
- __ bind(&fast_double_with_map_check);
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
- __ j(not_equal, &slow);
- __ bind(&fast_double_without_map_check);
- // If the value is a number, store it as a double in the FastDoubleElements
- // array.
- __ StoreNumberToDoubleElements(eax, ebx, ecx, edx, xmm0,
- &transition_double_elements, false);
- __ ret(0);
-
- __ bind(&transition_smi_elements);
- __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
-
- // Transition the array appropriately depending on the value type.
- __ CheckMap(eax,
- masm->isolate()->factory()->heap_number_map(),
- &non_double_value,
- DONT_DO_SMI_CHECK);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
- // and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS,
- ebx,
- edi,
- &slow);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_ELEMENTS,
- ebx,
- edi,
- &slow);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
- FAST_ELEMENTS,
- ebx,
- edi,
- &slow);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
+ KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
+ &slow, kCheckMap, kDontIncrementLength);
+ KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
+ &slow, kDontCheckMap, kIncrementLength);
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 7d413b9..da17e29 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -1234,8 +1234,11 @@
__ test(left, Operand(left));
__ j(not_zero, &done, Label::kNear);
if (right->IsConstantOperand()) {
- if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
+ if (ToInteger32(LConstantOperand::cast(right)) < 0) {
DeoptimizeIf(no_condition, instr->environment());
+ } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
+ __ cmp(ToRegister(instr->temp()), Immediate(0));
+ DeoptimizeIf(less, instr->environment());
}
} else {
// Test the non-zero operand for negative sign.
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index f843f3b..38e7480 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -2238,6 +2238,7 @@
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
+ ASSERT(argument_count_ == 0);
allocator_->MarkAsOsrEntry();
current_block_->last_environment()->set_ast_id(instr->ast_id());
return AssignEnvironment(new(zone()) LOsrEntry);
@@ -2385,7 +2386,7 @@
HEnvironment* env = current_block_->last_environment();
- if (instr->arguments_pushed()) {
+ if (env->entry()->arguments_pushed()) {
int argument_count = env->arguments_environment()->parameter_count();
pop = new(zone()) LDrop(argument_count);
argument_count_ -= argument_count;
diff --git a/src/ic-inl.h b/src/ic-inl.h
index 6a86921..0e41093 100644
--- a/src/ic-inl.h
+++ b/src/ic-inl.h
@@ -79,6 +79,7 @@
void IC::SetTargetAtAddress(Address address, Code* target) {
ASSERT(target->is_inline_cache_stub() || target->is_compare_ic_stub());
+ Heap* heap = target->GetHeap();
Code* old_target = GetTargetAtAddress(address);
#ifdef DEBUG
// STORE_IC and KEYED_STORE_IC use Code::extra_ic_state() to mark
@@ -90,8 +91,11 @@
}
#endif
Assembler::set_target_address_at(address, target->instruction_start());
- target->GetHeap()->incremental_marking()->RecordCodeTargetPatch(address,
- target);
+ if (heap->gc_state() == Heap::MARK_COMPACT) {
+ heap->mark_compact_collector()->RecordCodeTargetPatch(address, target);
+ } else {
+ heap->incremental_marking()->RecordCodeTargetPatch(address, target);
+ }
PostPatching(address, target, old_target);
}
diff --git a/src/ic.h b/src/ic.h
index c86f316..8767f98 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -631,6 +631,18 @@
};
+enum KeyedStoreCheckMap {
+ kDontCheckMap,
+ kCheckMap
+};
+
+
+enum KeyedStoreIncrementLength {
+ kDontIncrementLength,
+ kIncrementLength
+};
+
+
class KeyedStoreIC: public KeyedIC {
public:
explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) {
@@ -638,7 +650,7 @@
}
MUST_USE_RESULT MaybeObject* Store(State state,
- StrictModeFlag strict_mode,
+ StrictModeFlag strict_mode,
Handle<Object> object,
Handle<Object> name,
Handle<Object> value,
diff --git a/src/incremental-marking-inl.h b/src/incremental-marking-inl.h
index 768fc91..bbe9a9d 100644
--- a/src/incremental-marking-inl.h
+++ b/src/incremental-marking-inl.h
@@ -111,7 +111,7 @@
if (FLAG_trace_gc) {
PrintPID("Hurrying incremental marking because of lack of progress\n");
}
- allocation_marking_factor_ = kMaxAllocationMarkingFactor;
+ marking_speed_ = kMaxMarkingSpeed;
}
}
@@ -125,27 +125,6 @@
}
-bool IncrementalMarking::MarkObjectAndPush(HeapObject* obj) {
- MarkBit mark_bit = Marking::MarkBitFrom(obj);
- if (!mark_bit.Get()) {
- WhiteToGreyAndPush(obj, mark_bit);
- return true;
- }
- return false;
-}
-
-
-bool IncrementalMarking::MarkObjectWithoutPush(HeapObject* obj) {
- MarkBit mark_bit = Marking::MarkBitFrom(obj);
- if (!mark_bit.Get()) {
- mark_bit.Set();
- MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
- return true;
- }
- return false;
-}
-
-
} } // namespace v8::internal
#endif // V8_INCREMENTAL_MARKING_INL_H_
diff --git a/src/incremental-marking.cc b/src/incremental-marking.cc
index 4b0c578..32a084d 100644
--- a/src/incremental-marking.cc
+++ b/src/incremental-marking.cc
@@ -44,7 +44,6 @@
state_(STOPPED),
marking_deque_memory_(NULL),
marking_deque_memory_committed_(false),
- marker_(this, heap->mark_compact_collector()),
steps_count_(0),
steps_took_(0),
longest_step_(0.0),
@@ -53,7 +52,7 @@
steps_count_since_last_gc_(0),
steps_took_since_last_gc_(0),
should_hurry_(false),
- allocation_marking_factor_(0),
+ marking_speed_(0),
allocated_(0),
no_marking_scope_depth_(0) {
}
@@ -82,17 +81,19 @@
Object* value,
Isolate* isolate) {
ASSERT(obj->IsHeapObject());
-
- // Fast cases should already be covered by RecordWriteStub.
- ASSERT(value->IsHeapObject());
- ASSERT(!value->IsHeapNumber());
- ASSERT(!value->IsString() ||
- value->IsConsString() ||
- value->IsSlicedString());
- ASSERT(Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(value))));
-
IncrementalMarking* marking = isolate->heap()->incremental_marking();
ASSERT(!marking->is_compacting_);
+
+ MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
+ int counter = chunk->write_barrier_counter();
+ if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) {
+ marking->write_barriers_invoked_since_last_step_ +=
+ MemoryChunk::kWriteBarrierCounterGranularity -
+ chunk->write_barrier_counter();
+ chunk->set_write_barrier_counter(
+ MemoryChunk::kWriteBarrierCounterGranularity);
+ }
+
marking->RecordWrite(obj, NULL, value);
}
@@ -100,8 +101,20 @@
void IncrementalMarking::RecordWriteForEvacuationFromCode(HeapObject* obj,
Object** slot,
Isolate* isolate) {
+ ASSERT(obj->IsHeapObject());
IncrementalMarking* marking = isolate->heap()->incremental_marking();
ASSERT(marking->is_compacting_);
+
+ MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
+ int counter = chunk->write_barrier_counter();
+ if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) {
+ marking->write_barriers_invoked_since_last_step_ +=
+ MemoryChunk::kWriteBarrierCounterGranularity -
+ chunk->write_barrier_counter();
+ chunk->set_write_barrier_counter(
+ MemoryChunk::kWriteBarrierCounterGranularity);
+ }
+
marking->RecordWrite(obj, slot, *slot);
}
@@ -226,6 +239,7 @@
}
}
+ // Marks the object grey and pushes it on the marking stack.
INLINE(static void MarkObject(Heap* heap, Object* obj)) {
HeapObject* heap_object = HeapObject::cast(obj);
MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
@@ -238,6 +252,20 @@
heap->incremental_marking()->WhiteToGreyAndPush(heap_object, mark_bit);
}
}
+
+ // Marks the object black without pushing it on the marking stack.
+ // Returns true if object needed marking and false otherwise.
+ INLINE(static bool MarkObjectWithoutPush(Heap* heap, Object* obj)) {
+ HeapObject* heap_object = HeapObject::cast(obj);
+ MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
+ if (Marking::IsWhite(mark_bit)) {
+ mark_bit.Set();
+ MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(),
+ heap_object->Size());
+ return true;
+ }
+ return false;
+ }
};
@@ -641,23 +669,6 @@
} else if (map == native_context_map) {
// Native contexts have weak fields.
IncrementalMarkingMarkingVisitor::VisitNativeContext(map, obj);
- } else if (map->instance_type() == MAP_TYPE) {
- Map* map = Map::cast(obj);
- heap_->ClearCacheOnMap(map);
-
- // When map collection is enabled we have to mark through map's
- // transitions and back pointers in a special way to make these links
- // weak. Only maps for subclasses of JSReceiver can have transitions.
- STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
- if (FLAG_collect_maps &&
- map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
- marker_.MarkMapContents(map);
- } else {
- IncrementalMarkingMarkingVisitor::VisitPointers(
- heap_,
- HeapObject::RawField(map, Map::kPointerFieldsBeginOffset),
- HeapObject::RawField(map, Map::kPointerFieldsEndOffset));
- }
} else {
MarkBit map_mark_bit = Marking::MarkBitFrom(map);
if (Marking::IsWhite(map_mark_bit)) {
@@ -776,11 +787,25 @@
allocated_ += allocated_bytes;
- if (allocated_ < kAllocatedThreshold) return;
+ if (allocated_ < kAllocatedThreshold &&
+ write_barriers_invoked_since_last_step_ <
+ kWriteBarriersInvokedThreshold) {
+ return;
+ }
if (state_ == MARKING && no_marking_scope_depth_ > 0) return;
- intptr_t bytes_to_process = allocated_ * allocation_marking_factor_;
+ // The marking speed is driven either by the allocation rate or by the rate
+ // at which we are having to check the color of objects in the write barrier.
+ // It is possible for a tight non-allocating loop to run a lot of write
+ // barriers before we get here and check them (marking can only take place on
+ // allocation), so to reduce the lumpiness we don't use the write barriers
+ // invoked since last step directly to determine the amount of work to do.
+ intptr_t bytes_to_process =
+ marking_speed_ * Max(allocated_, kWriteBarriersInvokedThreshold);
+ allocated_ = 0;
+ write_barriers_invoked_since_last_step_ = 0;
+
bytes_scanned_ += bytes_to_process;
double start = 0;
@@ -822,23 +847,6 @@
MarkObjectGreyDoNotEnqueue(ctx->normalized_map_cache());
IncrementalMarkingMarkingVisitor::VisitNativeContext(map, ctx);
- } else if (map->instance_type() == MAP_TYPE) {
- Map* map = Map::cast(obj);
- heap_->ClearCacheOnMap(map);
-
- // When map collection is enabled we have to mark through map's
- // transitions and back pointers in a special way to make these links
- // weak. Only maps for subclasses of JSReceiver can have transitions.
- STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
- if (FLAG_collect_maps &&
- map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
- marker_.MarkMapContents(map);
- } else {
- IncrementalMarkingMarkingVisitor::VisitPointers(
- heap_,
- HeapObject::RawField(map, Map::kPointerFieldsBeginOffset),
- HeapObject::RawField(map, Map::kPointerFieldsEndOffset));
- }
} else {
IncrementalMarkingMarkingVisitor::IterateBody(map, obj);
}
@@ -852,17 +860,15 @@
if (marking_deque_.IsEmpty()) MarkingComplete(action);
}
- allocated_ = 0;
-
steps_count_++;
steps_count_since_last_gc_++;
bool speed_up = false;
- if ((steps_count_ % kAllocationMarkingFactorSpeedupInterval) == 0) {
+ if ((steps_count_ % kMarkingSpeedAccellerationInterval) == 0) {
if (FLAG_trace_gc) {
PrintPID("Speed up marking after %d steps\n",
- static_cast<int>(kAllocationMarkingFactorSpeedupInterval));
+ static_cast<int>(kMarkingSpeedAccellerationInterval));
}
speed_up = true;
}
@@ -871,7 +877,7 @@
(old_generation_space_available_at_start_of_incremental_ < 10 * MB);
bool only_1_nth_of_space_that_was_available_still_left =
- (SpaceLeftInOldSpace() * (allocation_marking_factor_ + 1) <
+ (SpaceLeftInOldSpace() * (marking_speed_ + 1) <
old_generation_space_available_at_start_of_incremental_);
if (space_left_is_very_small ||
@@ -882,7 +888,7 @@
bool size_of_old_space_multiplied_by_n_during_marking =
(heap_->PromotedTotalSize() >
- (allocation_marking_factor_ + 1) *
+ (marking_speed_ + 1) *
old_generation_space_used_at_start_of_incremental_);
if (size_of_old_space_multiplied_by_n_during_marking) {
speed_up = true;
@@ -893,7 +899,7 @@
int64_t promoted_during_marking = heap_->PromotedTotalSize()
- old_generation_space_used_at_start_of_incremental_;
- intptr_t delay = allocation_marking_factor_ * MB;
+ intptr_t delay = marking_speed_ * MB;
intptr_t scavenge_slack = heap_->MaxSemiSpaceSize();
// We try to scan at at least twice the speed that we are allocating.
@@ -910,12 +916,12 @@
PrintPID("Postponing speeding up marking until marking starts\n");
}
} else {
- allocation_marking_factor_ += kAllocationMarkingFactorSpeedup;
- allocation_marking_factor_ = static_cast<int>(
- Min(kMaxAllocationMarkingFactor,
- static_cast<intptr_t>(allocation_marking_factor_ * 1.3)));
+ marking_speed_ += kMarkingSpeedAccellerationInterval;
+ marking_speed_ = static_cast<int>(
+ Min(kMaxMarkingSpeed,
+ static_cast<intptr_t>(marking_speed_ * 1.3)));
if (FLAG_trace_gc) {
- PrintPID("Marking speed increased to %d\n", allocation_marking_factor_);
+ PrintPID("Marking speed increased to %d\n", marking_speed_);
}
}
}
@@ -941,8 +947,9 @@
steps_count_since_last_gc_ = 0;
steps_took_since_last_gc_ = 0;
bytes_rescanned_ = 0;
- allocation_marking_factor_ = kInitialAllocationMarkingFactor;
+ marking_speed_ = kInitialMarkingSpeed;
bytes_scanned_ = 0;
+ write_barriers_invoked_since_last_step_ = 0;
}
diff --git a/src/incremental-marking.h b/src/incremental-marking.h
index 528ff37..1a86fcd 100644
--- a/src/incremental-marking.h
+++ b/src/incremental-marking.h
@@ -95,21 +95,23 @@
// progress in the face of the mutator creating new work for it. We start
// of at a moderate rate of work and gradually increase the speed of the
// incremental marker until it completes.
- // Do some marking every time this much memory has been allocated.
+ // Do some marking every time this much memory has been allocated or that many
+ // heavy (color-checking) write barriers have been invoked.
static const intptr_t kAllocatedThreshold = 65536;
+ static const intptr_t kWriteBarriersInvokedThreshold = 65536;
// Start off by marking this many times more memory than has been allocated.
- static const intptr_t kInitialAllocationMarkingFactor = 1;
+ static const intptr_t kInitialMarkingSpeed = 1;
// But if we are promoting a lot of data we need to mark faster to keep up
// with the data that is entering the old space through promotion.
static const intptr_t kFastMarking = 3;
// After this many steps we increase the marking/allocating factor.
- static const intptr_t kAllocationMarkingFactorSpeedupInterval = 1024;
+ static const intptr_t kMarkingSpeedAccellerationInterval = 1024;
// This is how much we increase the marking/allocating factor by.
- static const intptr_t kAllocationMarkingFactorSpeedup = 2;
- static const intptr_t kMaxAllocationMarkingFactor = 1000;
+ static const intptr_t kMarkingSpeedAccelleration = 2;
+ static const intptr_t kMaxMarkingSpeed = 1000;
void OldSpaceStep(intptr_t allocated) {
- Step(allocated * kFastMarking / kInitialAllocationMarkingFactor,
+ Step(allocated * kFastMarking / kInitialMarkingSpeed,
GC_VIA_STACK_GUARD);
}
@@ -136,7 +138,7 @@
// guaranteed to be rescanned or not guaranteed to survive.
//
// No slots in white objects should be recorded, as some slots are typed and
- // cannot be interpreted corrrectly if the underlying object does not survive
+ // cannot be interpreted correctly if the underlying object does not survive
// the incremental cycle (stays white).
INLINE(bool BaseRecordWrite(HeapObject* obj, Object** slot, Object* value));
INLINE(void RecordWrite(HeapObject* obj, Object** slot, Object* value));
@@ -175,16 +177,6 @@
return true;
}
- // Marks the object grey and pushes it on the marking stack.
- // Returns true if object needed marking and false otherwise.
- // This is for incremental marking only.
- INLINE(bool MarkObjectAndPush(HeapObject* obj));
-
- // Marks the object black without pushing it on the marking stack.
- // Returns true if object needed marking and false otherwise.
- // This is for incremental marking only.
- INLINE(bool MarkObjectWithoutPush(HeapObject* obj));
-
inline int steps_count() {
return steps_count_;
}
@@ -221,13 +213,13 @@
void NotifyOfHighPromotionRate() {
if (IsMarking()) {
- if (allocation_marking_factor_ < kFastMarking) {
+ if (marking_speed_ < kFastMarking) {
if (FLAG_trace_gc) {
PrintPID("Increasing marking speed to %d "
"due to high promotion rate\n",
static_cast<int>(kFastMarking));
}
- allocation_marking_factor_ = kFastMarking;
+ marking_speed_ = kFastMarking;
}
}
}
@@ -275,7 +267,6 @@
VirtualMemory* marking_deque_memory_;
bool marking_deque_memory_committed_;
MarkingDeque marking_deque_;
- Marker<IncrementalMarking> marker_;
int steps_count_;
double steps_took_;
@@ -286,9 +277,10 @@
double steps_took_since_last_gc_;
int64_t bytes_rescanned_;
bool should_hurry_;
- int allocation_marking_factor_;
+ int marking_speed_;
intptr_t bytes_scanned_;
intptr_t allocated_;
+ intptr_t write_barriers_invoked_since_last_step_;
int no_marking_scope_depth_;
diff --git a/src/json-parser.h b/src/json-parser.h
index a4db130..8eb4f67 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -71,11 +71,11 @@
inline void AdvanceSkipWhitespace() {
do {
Advance();
- } while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' ');
+ } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r');
}
inline void SkipWhitespace() {
- while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' ') {
+ while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') {
Advance();
}
}
@@ -563,6 +563,53 @@
AdvanceSkipWhitespace();
return Handle<String>(isolate()->heap()->empty_string());
}
+
+ if (seq_ascii && is_symbol) {
+ // Fast path for existing symbols. If the the string being parsed is not
+ // a known symbol, contains backslashes or unexpectedly reaches the end of
+ // string, return with an empty handle.
+ uint32_t running_hash = isolate()->heap()->HashSeed();
+ int position = position_;
+ uc32 c0 = c0_;
+ do {
+ if (c0 == '\\') {
+ return SlowScanJsonString<SeqAsciiString, char>(source_,
+ position_,
+ position);
+ }
+ if (c0_ < 0x20) return Handle<String>::null();
+ running_hash = StringHasher::AddCharacterCore(running_hash, c0);
+ position++;
+ if (position >= source_length_) return Handle<String>::null();
+ c0 = seq_source_->SeqAsciiStringGet(position);
+ } while (c0 != '"');
+ int length = position - position_;
+ uint32_t hash = (length <= String::kMaxHashCalcLength)
+ ? StringHasher::GetHashCore(running_hash) : length;
+ Vector<const char> string_vector(
+ seq_source_->GetChars() + position_, length);
+ SymbolTable* symbol_table = isolate()->heap()->symbol_table();
+ uint32_t capacity = symbol_table->Capacity();
+ uint32_t entry = SymbolTable::FirstProbe(hash, capacity);
+ uint32_t count = 1;
+ while (true) {
+ Object* element = symbol_table->KeyAt(entry);
+ if (element == isolate()->heap()->raw_unchecked_undefined_value()) {
+ // Lookup failure.
+ break;
+ }
+ if (element != isolate()->heap()->raw_unchecked_the_hole_value() &&
+ String::cast(element)->IsAsciiEqualTo(string_vector)) {
+ // Lookup success, update the current position.
+ position_ = position;
+ // Advance past the last '"'.
+ AdvanceSkipWhitespace();
+ return Handle<String>(String::cast(element));
+ }
+ entry = SymbolTable::NextProbe(entry, count++, capacity);
+ }
+ }
+
int beg_pos = position_;
// Fast case for ASCII only without escape characters.
do {
diff --git a/src/lithium.h b/src/lithium.h
index e1cd52a..b4eb2bb 100644
--- a/src/lithium.h
+++ b/src/lithium.h
@@ -133,13 +133,15 @@
// index in the upper bits.
static const int kPolicyWidth = 3;
static const int kLifetimeWidth = 1;
- static const int kVirtualRegisterWidth = 18;
+ static const int kVirtualRegisterWidth = 15;
static const int kPolicyShift = kKindFieldWidth;
static const int kLifetimeShift = kPolicyShift + kPolicyWidth;
static const int kVirtualRegisterShift = kLifetimeShift + kLifetimeWidth;
static const int kFixedIndexShift =
kVirtualRegisterShift + kVirtualRegisterWidth;
+ static const int kFixedIndexWidth = 32 - kFixedIndexShift;
+ STATIC_ASSERT(kFixedIndexWidth > 5);
class PolicyField : public BitField<Policy, kPolicyShift, kPolicyWidth> { };
@@ -154,8 +156,8 @@
};
static const int kMaxVirtualRegisters = 1 << kVirtualRegisterWidth;
- static const int kMaxFixedIndex = 63;
- static const int kMinFixedIndex = -64;
+ static const int kMaxFixedIndex = (1 << kFixedIndexWidth) - 1;
+ static const int kMinFixedIndex = -(1 << kFixedIndexWidth);
bool HasAnyPolicy() const {
return policy() == ANY;
diff --git a/src/mark-compact-inl.h b/src/mark-compact-inl.h
index 2f7e31f..10773e7 100644
--- a/src/mark-compact-inl.h
+++ b/src/mark-compact-inl.h
@@ -52,43 +52,23 @@
}
-bool MarkCompactCollector::MarkObjectAndPush(HeapObject* obj) {
- if (MarkObjectWithoutPush(obj)) {
- marking_deque_.PushBlack(obj);
- return true;
- }
- return false;
-}
-
-
void MarkCompactCollector::MarkObject(HeapObject* obj, MarkBit mark_bit) {
ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
if (!mark_bit.Get()) {
mark_bit.Set();
MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
- ProcessNewlyMarkedObject(obj);
+ ASSERT(IsMarked(obj));
+ ASSERT(HEAP->Contains(obj));
+ marking_deque_.PushBlack(obj);
}
}
-bool MarkCompactCollector::MarkObjectWithoutPush(HeapObject* obj) {
- MarkBit mark_bit = Marking::MarkBitFrom(obj);
- if (!mark_bit.Get()) {
- SetMark(obj, mark_bit);
- return true;
- }
- return false;
-}
-
-
void MarkCompactCollector::SetMark(HeapObject* obj, MarkBit mark_bit) {
ASSERT(!mark_bit.Get());
ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
mark_bit.Set();
MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
- if (obj->IsMap()) {
- heap_->ClearCacheOnMap(Map::cast(obj));
- }
}
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 7c03a49..be70dc3 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -68,8 +68,7 @@
migration_slots_buffer_(NULL),
heap_(NULL),
code_flusher_(NULL),
- encountered_weak_maps_(NULL),
- marker_(this, this) { }
+ encountered_weak_maps_(NULL) { }
#ifdef DEBUG
@@ -340,6 +339,11 @@
if (!compacting_) {
ASSERT(evacuation_candidates_.length() == 0);
+#ifdef ENABLE_GDB_JIT_INTERFACE
+ // If GDBJIT interface is active disable compaction.
+ if (FLAG_gdbjit) return false;
+#endif
+
CollectEvacuationCandidates(heap()->old_pointer_space());
CollectEvacuationCandidates(heap()->old_data_space());
@@ -779,13 +783,6 @@
ASSERT(!FLAG_never_compact || !FLAG_always_compact);
-#ifdef ENABLE_GDB_JIT_INTERFACE
- if (FLAG_gdbjit) {
- // If GDBJIT interface is active disable compaction.
- compacting_collection_ = false;
- }
-#endif
-
// Clear marking bits if incremental marking is aborted.
if (was_marked_incrementally_ && abort_incremental_marking_) {
heap()->incremental_marking()->Abort();
@@ -1067,11 +1064,23 @@
}
}
+ // Marks the object black and pushes it on the marking stack.
INLINE(static void MarkObject(Heap* heap, HeapObject* object)) {
MarkBit mark = Marking::MarkBitFrom(object);
heap->mark_compact_collector()->MarkObject(object, mark);
}
+ // Marks the object black without pushing it on the marking stack.
+ // Returns true if object needed marking and false otherwise.
+ INLINE(static bool MarkObjectWithoutPush(Heap* heap, HeapObject* object)) {
+ MarkBit mark_bit = Marking::MarkBitFrom(object);
+ if (!mark_bit.Get()) {
+ heap->mark_compact_collector()->SetMark(object, mark_bit);
+ return true;
+ }
+ return false;
+ }
+
// Mark object pointed to by p.
INLINE(static void MarkObjectByPointer(MarkCompactCollector* collector,
Object** anchor_slot,
@@ -1879,97 +1888,6 @@
};
-void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) {
- ASSERT(IsMarked(object));
- ASSERT(HEAP->Contains(object));
- if (object->IsMap()) {
- Map* map = Map::cast(object);
- heap_->ClearCacheOnMap(map);
-
- // When map collection is enabled we have to mark through map's transitions
- // in a special way to make transition links weak. Only maps for subclasses
- // of JSReceiver can have transitions.
- STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
- if (FLAG_collect_maps && map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
- marker_.MarkMapContents(map);
- } else {
- marking_deque_.PushBlack(map);
- }
- } else {
- marking_deque_.PushBlack(object);
- }
-}
-
-
-// Force instantiation of template instances.
-template void Marker<IncrementalMarking>::MarkMapContents(Map* map);
-template void Marker<MarkCompactCollector>::MarkMapContents(Map* map);
-
-
-template <class T>
-void Marker<T>::MarkMapContents(Map* map) {
- // Make sure that the back pointer stored either in the map itself or inside
- // its transitions array is marked. Treat pointers in the transitions array as
- // weak and also mark that array to prevent visiting it later.
- base_marker()->MarkObjectAndPush(HeapObject::cast(map->GetBackPointer()));
-
- Object** transitions_slot =
- HeapObject::RawField(map, Map::kTransitionsOrBackPointerOffset);
- Object* transitions = *transitions_slot;
- if (transitions->IsTransitionArray()) {
- MarkTransitionArray(reinterpret_cast<TransitionArray*>(transitions));
- } else {
- // Already marked by marking map->GetBackPointer().
- ASSERT(transitions->IsMap() || transitions->IsUndefined());
- }
-
- // Mark the Object* fields of the Map. Since the transitions array has been
- // marked already, it is fine that one of these fields contains a pointer to
- // it.
- Object** start_slot =
- HeapObject::RawField(map, Map::kPointerFieldsBeginOffset);
- Object** end_slot = HeapObject::RawField(map, Map::kPointerFieldsEndOffset);
- for (Object** slot = start_slot; slot < end_slot; slot++) {
- Object* obj = *slot;
- if (!obj->NonFailureIsHeapObject()) continue;
- mark_compact_collector()->RecordSlot(start_slot, slot, obj);
- base_marker()->MarkObjectAndPush(reinterpret_cast<HeapObject*>(obj));
- }
-}
-
-
-template <class T>
-void Marker<T>::MarkTransitionArray(TransitionArray* transitions) {
- if (!base_marker()->MarkObjectWithoutPush(transitions)) return;
- Object** transitions_start = transitions->data_start();
-
- // We don't have to record the descriptors_pointer slot since the cell space
- // is not compacted.
- JSGlobalPropertyCell* descriptors_cell = transitions->descriptors_pointer();
- base_marker()->MarkObjectAndPush(descriptors_cell);
-
- if (transitions->HasPrototypeTransitions()) {
- // Mark prototype transitions array but don't push it into marking stack.
- // This will make references from it weak. We will clean dead prototype
- // transitions in ClearNonLiveTransitions.
- Object** proto_trans_slot = transitions->GetPrototypeTransitionsSlot();
- HeapObject* prototype_transitions = HeapObject::cast(*proto_trans_slot);
- base_marker()->MarkObjectWithoutPush(prototype_transitions);
- mark_compact_collector()->RecordSlot(
- transitions_start, proto_trans_slot, prototype_transitions);
- }
-
- for (int i = 0; i < transitions->number_of_transitions(); ++i) {
- Object** key_slot = transitions->GetKeySlot(i);
- Object* key = *key_slot;
- if (key->IsHeapObject()) {
- base_marker()->MarkObjectAndPush(HeapObject::cast(key));
- mark_compact_collector()->RecordSlot(transitions_start, key_slot, key);
- }
- }
-}
-
-
// Fill the marking stack with overflowed objects returned by the given
// iterator. Stop when the marking stack is filled or the end of the space
// is reached, whichever comes first.
@@ -4083,6 +4001,20 @@
}
+void MarkCompactCollector::RecordCodeTargetPatch(Address pc, Code* target) {
+ ASSERT(heap()->gc_state() == Heap::MARK_COMPACT);
+ if (is_compacting()) {
+ Code* host = heap()->isolate()->inner_pointer_to_code_cache()->
+ GcSafeFindCodeForInnerPointer(pc);
+ MarkBit mark_bit = Marking::MarkBitFrom(host);
+ if (Marking::IsBlack(mark_bit)) {
+ RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host);
+ RecordRelocSlot(&rinfo, target);
+ }
+ }
+}
+
+
static inline SlotsBuffer::SlotType DecodeSlotType(
SlotsBuffer::ObjectSlot slot) {
return static_cast<SlotsBuffer::SlotType>(reinterpret_cast<intptr_t>(slot));
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 0f19d2c..deade29 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -403,33 +403,6 @@
};
-// -------------------------------------------------------------------------
-// Marker shared between incremental and non-incremental marking
-template<class BaseMarker> class Marker {
- public:
- Marker(BaseMarker* base_marker, MarkCompactCollector* mark_compact_collector)
- : base_marker_(base_marker),
- mark_compact_collector_(mark_compact_collector) {}
-
- // Mark pointers in a Map and its DescriptorArray together, possibly
- // treating transitions or back pointers weak.
- void MarkMapContents(Map* map);
- void MarkTransitionArray(TransitionArray* transitions);
-
- private:
- BaseMarker* base_marker() {
- return base_marker_;
- }
-
- MarkCompactCollector* mark_compact_collector() {
- return mark_compact_collector_;
- }
-
- BaseMarker* base_marker_;
- MarkCompactCollector* mark_compact_collector_;
-};
-
-
// Defined in isolate.h.
class ThreadLocalTop;
@@ -572,6 +545,7 @@
void RecordRelocSlot(RelocInfo* rinfo, Object* target);
void RecordCodeEntrySlot(Address slot, Code* target);
+ void RecordCodeTargetPatch(Address pc, Code* target);
INLINE(void RecordSlot(Object** anchor_slot, Object** slot, Object* object));
@@ -656,8 +630,6 @@
friend class MarkCompactMarkingVisitor;
friend class CodeMarkingVisitor;
friend class SharedFunctionInfoMarkingVisitor;
- friend class Marker<IncrementalMarking>;
- friend class Marker<MarkCompactCollector>;
// Mark non-optimize code for functions inlined into the given optimized
// code. This will prevent it from being flushed.
@@ -675,25 +647,13 @@
void AfterMarking();
// Marks the object black and pushes it on the marking stack.
- // Returns true if object needed marking and false otherwise.
- // This is for non-incremental marking only.
- INLINE(bool MarkObjectAndPush(HeapObject* obj));
-
- // Marks the object black and pushes it on the marking stack.
// This is for non-incremental marking only.
INLINE(void MarkObject(HeapObject* obj, MarkBit mark_bit));
- // Marks the object black without pushing it on the marking stack.
- // Returns true if object needed marking and false otherwise.
- // This is for non-incremental marking only.
- INLINE(bool MarkObjectWithoutPush(HeapObject* obj));
-
// Marks the object black assuming that it is not yet marked.
// This is for non-incremental marking only.
INLINE(void SetMark(HeapObject* obj, MarkBit mark_bit));
- void ProcessNewlyMarkedObject(HeapObject* obj);
-
// Mark the heap roots and all objects reachable from them.
void MarkRoots(RootMarkingVisitor* visitor);
@@ -796,7 +756,6 @@
MarkingDeque marking_deque_;
CodeFlusher* code_flusher_;
Object* encountered_weak_maps_;
- Marker<MarkCompactCollector> marker_;
List<Page*> evacuation_candidates_;
List<Code*> invalidated_code_;
diff --git a/src/messages.js b/src/messages.js
index 4b389a0..1ead322 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -229,7 +229,7 @@
"strict_catch_variable", ["Catch variable may not be eval or arguments in strict mode"],
"too_many_arguments", ["Too many arguments in function call (only 32766 allowed)"],
"too_many_parameters", ["Too many parameters in function definition (only 32766 allowed)"],
- "too_many_variables", ["Too many variables declared (only 32767 allowed)"],
+ "too_many_variables", ["Too many variables declared (only 65535 allowed)"],
"strict_param_name", ["Parameter name eval or arguments is not allowed in strict mode"],
"strict_param_dupe", ["Strict mode function may not have duplicate parameter names"],
"strict_var_name", ["Variable name may not be eval or arguments in strict mode"],
@@ -532,8 +532,8 @@
/**
- * Returns the name of script if available, contents of sourceURL comment
- * otherwise. See
+ * If sourceURL comment is available and script starts at zero returns sourceURL
+ * comment contents. Otherwise, script name is returned. See
* http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
* for details on using //@ sourceURL comment to identify scritps that don't
* have name.
@@ -542,14 +542,15 @@
* otherwise.
*/
function ScriptNameOrSourceURL() {
- if (this.name) {
+ if (this.line_offset > 0 || this.column_offset > 0) {
return this.name;
}
// The result is cached as on long scripts it takes noticable time to search
// for the sourceURL.
- if (this.hasCachedNameOrSourceURL)
- return this.cachedNameOrSourceURL;
+ if (this.hasCachedNameOrSourceURL) {
+ return this.cachedNameOrSourceURL;
+ }
this.hasCachedNameOrSourceURL = true;
// TODO(608): the spaces in a regexp below had to be escaped as \040
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index 801ca2c..a4563a6 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -580,17 +580,20 @@
// See Assembler::nop(type).
ASSERT(type < 32);
uint32_t opcode = GetOpcodeField(instr);
+ uint32_t function = GetFunctionField(instr);
uint32_t rt = GetRt(instr);
- uint32_t rs = GetRs(instr);
+ uint32_t rd = GetRd(instr);
uint32_t sa = GetSa(instr);
- // nop(type) == sll(zero_reg, zero_reg, type);
- // Technically all these values will be 0 but
- // this makes more sense to the reader.
+ // Traditional mips nop == sll(zero_reg, zero_reg, 0)
+ // When marking non-zero type, use sll(zero_reg, at, type)
+ // to avoid use of mips ssnop and ehb special encodings
+ // of the sll instruction.
- bool ret = (opcode == SLL &&
- rt == static_cast<uint32_t>(ToNumber(zero_reg)) &&
- rs == static_cast<uint32_t>(ToNumber(zero_reg)) &&
+ Register nop_rt_reg = (type == 0) ? zero_reg : at;
+ bool ret = (opcode == SPECIAL && function == SLL &&
+ rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
+ rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
sa == type);
return ret;
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index 7163770..ee4daad 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -663,10 +663,13 @@
FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
};
- // Type == 0 is the default non-marking type.
+ // Type == 0 is the default non-marking nop. For mips this is a
+ // sll(zero_reg, zero_reg, 0). We use rt_reg == at for non-zero
+ // marking, to avoid conflict with ssnop and ehb instructions.
void nop(unsigned int type = 0) {
ASSERT(type < 32);
- sll(zero_reg, zero_reg, type, true);
+ Register nop_rt_reg = (type == 0) ? zero_reg : at;
+ sll(zero_reg, nop_rt_reg, type, true);
}
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 86af0dd..ee3127a 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -7512,6 +7512,11 @@
}
+bool CodeStub::CanUseFPRegisters() {
+ return CpuFeatures::IsSupported(FPU);
+}
+
+
// Takes the input in 3 registers: address_ value_ and object_. A pointer to
// the value has just been written into the object, now this stub makes sure
// we keep the GC informed. The word in the object where the value has been
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index bfa2425..ed8a2e2 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -2208,44 +2208,17 @@
ASSERT(prop != NULL);
ASSERT(prop->key()->AsLiteral() != NULL);
- // If the assignment starts a block of assignments to the same object,
- // change to slow case to avoid the quadratic behavior of repeatedly
- // adding fast properties.
- if (expr->starts_initialization_block()) {
- __ push(result_register());
- __ lw(t0, MemOperand(sp, kPointerSize)); // Receiver is now under value.
- __ push(t0);
- __ CallRuntime(Runtime::kToSlowProperties, 1);
- __ pop(result_register());
- }
-
// Record source code position before IC call.
SetSourcePosition(expr->position());
__ mov(a0, result_register()); // Load the value.
__ li(a2, Operand(prop->key()->AsLiteral()->handle()));
- // Load receiver to a1. Leave a copy in the stack if needed for turning the
- // receiver into fast case.
- if (expr->ends_initialization_block()) {
- __ lw(a1, MemOperand(sp));
- } else {
- __ pop(a1);
- }
+ __ pop(a1);
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
- // If the assignment ends an initialization block, revert to fast case.
- if (expr->ends_initialization_block()) {
- __ push(v0); // Result of assignment, saved even if not needed.
- // Receiver is under the result value.
- __ lw(t0, MemOperand(sp, kPointerSize));
- __ push(t0);
- __ CallRuntime(Runtime::kToFastProperties, 1);
- __ pop(v0);
- __ Drop(1);
- }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(v0);
}
@@ -2254,18 +2227,6 @@
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
// Assignment to a property, using a keyed store IC.
- // If the assignment starts a block of assignments to the same object,
- // change to slow case to avoid the quadratic behavior of repeatedly
- // adding fast properties.
- if (expr->starts_initialization_block()) {
- __ push(result_register());
- // Receiver is now under the key and value.
- __ lw(t0, MemOperand(sp, 2 * kPointerSize));
- __ push(t0);
- __ CallRuntime(Runtime::kToSlowProperties, 1);
- __ pop(result_register());
- }
-
// Record source code position before IC call.
SetSourcePosition(expr->position());
// Call keyed store IC.
@@ -2275,29 +2236,13 @@
// - a2 is the receiver.
__ mov(a0, result_register());
__ pop(a1); // Key.
- // Load receiver to a2. Leave a copy in the stack if needed for turning the
- // receiver into fast case.
- if (expr->ends_initialization_block()) {
- __ lw(a2, MemOperand(sp));
- } else {
- __ pop(a2);
- }
+ __ pop(a2);
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
- // If the assignment ends an initialization block, revert to fast case.
- if (expr->ends_initialization_block()) {
- __ push(v0); // Result of assignment, saved even if not needed.
- // Receiver is under the result value.
- __ lw(t0, MemOperand(sp, kPointerSize));
- __ push(t0);
- __ CallRuntime(Runtime::kToFastProperties, 1);
- __ pop(v0);
- __ Drop(1);
- }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(v0);
}
@@ -2759,27 +2704,31 @@
__ Branch(if_false, eq, a2, Operand(t0));
// Look for valueOf symbol in the descriptor array, and indicate false if
- // found. The type is not checked, so if it is a transition it is a false
- // negative.
- __ LoadInstanceDescriptors(a1, t0, a3);
- __ lw(a3, FieldMemOperand(t0, FixedArray::kLengthOffset));
- // t0: descriptor array
- // a3: length of descriptor array
- // Calculate the end of the descriptor array.
+ // found. Since we omit an enumeration index check, if it is added via a
+ // transition that shares its descriptor array, this is a false positive.
+ Label entry, loop, done;
+
+ // Skip loop if no descriptors are valid.
+ __ NumberOfOwnDescriptors(a3, a1);
+ __ Branch(&done, eq, a3, Operand(zero_reg));
+
+ __ LoadInstanceDescriptors(a1, t0, a2);
+ // t0: descriptor array.
+ // a3: valid entries in the descriptor array.
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagSize == 1);
STATIC_ASSERT(kPointerSize == 4);
- __ Addu(a2, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ li(at, Operand(DescriptorArray::kDescriptorSize));
+ __ Mul(a3, a3, at);
+ // Calculate location of the first key name.
+ __ Addu(t0, t0, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag));
+ // Calculate the end of the descriptor array.
+ __ mov(a2, t0);
__ sll(t1, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(a2, a2, t1);
- // Calculate location of the first key name.
- __ Addu(t0,
- t0,
- Operand(DescriptorArray::kFirstOffset - kHeapObjectTag));
// Loop through all the keys in the descriptor array. If one of these is the
// symbol valueOf the result is false.
- Label entry, loop;
// The use of t2 to store the valueOf symbol asumes that it is not otherwise
// used in the loop below.
__ LoadRoot(t2, Heap::kvalue_of_symbolRootIndex);
@@ -2791,7 +2740,8 @@
__ bind(&entry);
__ Branch(&loop, ne, t0, Operand(a2));
- // If a valueOf property is not found on the object check that it's
+ __ bind(&done);
+ // If a valueOf property is not found on the object check that its
// prototype is the un-modified String prototype. If not result is false.
__ lw(a2, FieldMemOperand(a1, Map::kPrototypeOffset));
__ JumpIfSmi(a2, if_false);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 2ad6452..e9edd48 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -2069,6 +2069,7 @@
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
+ ASSERT(argument_count_ == 0);
allocator_->MarkAsOsrEntry();
current_block_->last_environment()->set_ast_id(instr->ast_id());
return AssignEnvironment(new(zone()) LOsrEntry);
@@ -2208,7 +2209,7 @@
HEnvironment* env = current_block_->last_environment();
- if (instr->arguments_pushed()) {
+ if (env->entry()->arguments_pushed()) {
int argument_count = env->arguments_environment()->parameter_count();
pop = new(zone()) LDrop(argument_count);
argument_count_ -= argument_count;
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 7ded494..fe703da 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -5299,20 +5299,37 @@
Register temp = descriptors;
lw(temp, FieldMemOperand(map, Map::kTransitionsOrBackPointerOffset));
- Label ok, fail;
+ Label ok, fail, load_from_back_pointer;
CheckMap(temp,
scratch,
isolate()->factory()->fixed_array_map(),
&fail,
DONT_DO_SMI_CHECK);
- lw(descriptors, FieldMemOperand(temp, TransitionArray::kDescriptorsOffset));
+ lw(temp, FieldMemOperand(temp, TransitionArray::kDescriptorsPointerOffset));
+ lw(descriptors, FieldMemOperand(temp, JSGlobalPropertyCell::kValueOffset));
jmp(&ok);
+
bind(&fail);
+ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
+ Branch(&load_from_back_pointer, ne, temp, Operand(scratch));
LoadRoot(descriptors, Heap::kEmptyDescriptorArrayRootIndex);
+ jmp(&ok);
+
+ bind(&load_from_back_pointer);
+ lw(temp, FieldMemOperand(temp, Map::kTransitionsOrBackPointerOffset));
+ lw(temp, FieldMemOperand(temp, TransitionArray::kDescriptorsPointerOffset));
+ lw(descriptors, FieldMemOperand(temp, JSGlobalPropertyCell::kValueOffset));
+
bind(&ok);
}
+void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
+ lw(dst, FieldMemOperand(map, Map::kBitField3Offset));
+ DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
+}
+
+
void MacroAssembler::EnumLength(Register dst, Register map) {
STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
lw(dst, FieldMemOperand(map, Map::kBitField3Offset));
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 2a77d6c..dcbeb9f 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -1400,7 +1400,15 @@
Register descriptors,
Register scratch);
void EnumLength(Register dst, Register map);
+ void NumberOfOwnDescriptors(Register dst, Register map);
+ template<typename Field>
+ void DecodeField(Register reg) {
+ static const int shift = Field::kShift;
+ static const int mask = (Field::kMask >> shift) << kSmiTagSize;
+ srl(reg, reg, shift);
+ And(reg, reg, Operand(mask));
+ }
// Activation support.
void EnterFrame(StackFrame::Type type);
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index d569161..6195bf5 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -905,7 +905,7 @@
if (valid_entries == -1) valid_entries = number_of_descriptors();
String* current_key = NULL;
uint32_t current = 0;
- for (int i = 0; i < valid_entries; i++) {
+ for (int i = 0; i < number_of_descriptors(); i++) {
String* key = GetSortedKey(i);
if (key == current_key) {
PrintDescriptors();
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 36d0b6c..e47cec7 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1906,11 +1906,17 @@
}
+void DescriptorArray::SetNumberOfDescriptors(int number_of_descriptors) {
+ WRITE_FIELD(
+ this, kDescriptorLengthOffset, Smi::FromInt(number_of_descriptors));
+}
+
+
// Perform a binary search in a fixed array. Low and high are entry indices. If
// there are three entries in this array it should be called with low=0 and
// high=2.
-template<typename T>
-int BinarySearch(T* array, String* name, int low, int high) {
+template<SearchMode search_mode, typename T>
+int BinarySearch(T* array, String* name, int low, int high, int valid_entries) {
uint32_t hash = name->Hash();
int limit = high;
@@ -1932,12 +1938,18 @@
int sort_index = array->GetSortedKeyIndex(low);
String* entry = array->GetKey(sort_index);
if (entry->Hash() != hash) break;
- if (entry->Equals(name)) return sort_index;
+ if (entry->Equals(name)) {
+ if (search_mode == ALL_ENTRIES || sort_index < valid_entries) {
+ return sort_index;
+ }
+ return T::kNotFound;
+ }
}
return T::kNotFound;
}
+
// Perform a linear search in this fixed array. len is the number of entry
// indices that are valid.
template<SearchMode search_mode, typename T>
@@ -1976,13 +1988,15 @@
// Fast case: do linear search for small arrays.
const int kMaxElementsForLinearSearch = 8;
- if (search_mode == VALID_ENTRIES ||
- (search_mode == ALL_ENTRIES && nof < kMaxElementsForLinearSearch)) {
+ if ((search_mode == ALL_ENTRIES &&
+ nof <= kMaxElementsForLinearSearch) ||
+ (search_mode == VALID_ENTRIES &&
+ valid_entries <= (kMaxElementsForLinearSearch * 3))) {
return LinearSearch<search_mode>(array, name, nof, valid_entries);
}
// Slow case: perform binary search.
- return BinarySearch(array, name, 0, nof - 1);
+ return BinarySearch<search_mode>(array, name, 0, nof - 1, valid_entries);
}
@@ -2138,11 +2152,30 @@
}
+void DescriptorArray::Set(int descriptor_number, Descriptor* desc) {
+ // Range check.
+ ASSERT(descriptor_number < number_of_descriptors());
+ ASSERT(desc->GetDetails().descriptor_index() <=
+ number_of_descriptors());
+ ASSERT(desc->GetDetails().descriptor_index() > 0);
+
+ set(ToKeyIndex(descriptor_number), desc->GetKey());
+ set(ToValueIndex(descriptor_number), desc->GetValue());
+ set(ToDetailsIndex(descriptor_number), desc->GetDetails().AsSmi());
+}
+
+
+void DescriptorArray::EraseDescriptor(Heap* heap, int descriptor_number) {
+ set_null_unchecked(heap, ToKeyIndex(descriptor_number));
+ set_null_unchecked(heap, ToValueIndex(descriptor_number));
+}
+
+
void DescriptorArray::Append(Descriptor* desc,
- const WhitenessWitness& witness,
- int number_of_set_descriptors) {
- int descriptor_number = number_of_set_descriptors;
+ const WhitenessWitness& witness) {
+ int descriptor_number = number_of_descriptors();
int enumeration_index = descriptor_number + 1;
+ SetNumberOfDescriptors(descriptor_number + 1);
desc->SetEnumerationIndex(enumeration_index);
Set(descriptor_number, desc, witness);
@@ -2160,6 +2193,27 @@
}
+void DescriptorArray::Append(Descriptor* desc) {
+ int descriptor_number = number_of_descriptors();
+ int enumeration_index = descriptor_number + 1;
+ SetNumberOfDescriptors(descriptor_number + 1);
+ desc->SetEnumerationIndex(enumeration_index);
+ Set(descriptor_number, desc);
+
+ uint32_t hash = desc->GetKey()->Hash();
+
+ int insertion;
+
+ for (insertion = descriptor_number; insertion > 0; --insertion) {
+ String* key = GetSortedKey(insertion - 1);
+ if (key->Hash() <= hash) break;
+ SetSortedKey(insertion, GetSortedKeyIndex(insertion - 1));
+ }
+
+ SetSortedKey(insertion, descriptor_number);
+}
+
+
void DescriptorArray::SwapSortedKeys(int first, int second) {
int first_key = GetSortedKeyIndex(first);
SetSortedKey(first, GetSortedKeyIndex(second));
@@ -3514,17 +3568,31 @@
}
+enum TransitionsKind { DESCRIPTORS_HOLDER, FULL_TRANSITION_ARRAY };
+
+
// If the descriptor is using the empty transition array, install a new empty
// transition array that will have place for an element transition.
-static MaybeObject* EnsureHasTransitionArray(Map* map) {
- if (map->HasTransitionArray()) return map;
-
+static MaybeObject* EnsureHasTransitionArray(Map* map, TransitionsKind kind) {
TransitionArray* transitions;
- JSGlobalPropertyCell* pointer = map->RetrieveDescriptorsPointer();
- MaybeObject* maybe_transitions = TransitionArray::Allocate(0, pointer);
- if (!maybe_transitions->To(&transitions)) return maybe_transitions;
-
- transitions->set_back_pointer_storage(map->GetBackPointer());
+ MaybeObject* maybe_transitions;
+ if (map->HasTransitionArray()) {
+ if (kind != FULL_TRANSITION_ARRAY ||
+ map->transitions()->IsFullTransitionArray()) {
+ return map;
+ }
+ maybe_transitions = map->transitions()->ExtendToFullTransitionArray();
+ if (!maybe_transitions->To(&transitions)) return maybe_transitions;
+ } else {
+ JSGlobalPropertyCell* pointer = map->RetrieveDescriptorsPointer();
+ if (kind == FULL_TRANSITION_ARRAY) {
+ maybe_transitions = TransitionArray::Allocate(0, pointer);
+ } else {
+ maybe_transitions = TransitionArray::AllocateDescriptorsHolder(pointer);
+ }
+ if (!maybe_transitions->To(&transitions)) return maybe_transitions;
+ transitions->set_back_pointer_storage(map->GetBackPointer());
+ }
map->set_transitions(transitions);
return transitions;
}
@@ -3532,7 +3600,8 @@
MaybeObject* Map::SetDescriptors(DescriptorArray* value) {
ASSERT(!is_shared());
- MaybeObject* maybe_failure = EnsureHasTransitionArray(this);
+ MaybeObject* maybe_failure =
+ EnsureHasTransitionArray(this, DESCRIPTORS_HOLDER);
if (maybe_failure->IsFailure()) return maybe_failure;
ASSERT(NumberOfOwnDescriptors() <= value->number_of_descriptors());
@@ -3591,8 +3660,8 @@
const DescriptorArray::WhitenessWitness& witness) {
DescriptorArray* descriptors = instance_descriptors();
int number_of_own_descriptors = NumberOfOwnDescriptors();
- ASSERT(number_of_own_descriptors < descriptors->number_of_descriptors());
- descriptors->Append(desc, witness, number_of_own_descriptors);
+ ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
+ descriptors->Append(desc, witness);
SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
}
@@ -3642,11 +3711,13 @@
}
-MaybeObject* Map::AddTransition(String* key, Map* target) {
+MaybeObject* Map::AddTransition(String* key,
+ Map* target,
+ SimpleTransitionFlag flag) {
if (HasTransitionArray()) return transitions()->CopyInsert(key, target);
JSGlobalPropertyCell* descriptors_pointer = RetrieveDescriptorsPointer();
return TransitionArray::NewWith(
- key, target, descriptors_pointer, GetBackPointer());
+ flag, key, target, descriptors_pointer, GetBackPointer());
}
@@ -3661,7 +3732,8 @@
MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) {
- MaybeObject* allow_elements = EnsureHasTransitionArray(this);
+ MaybeObject* allow_elements =
+ EnsureHasTransitionArray(this, FULL_TRANSITION_ARRAY);
if (allow_elements->IsFailure()) return allow_elements;
transitions()->set_elements_transition(transitioned_map);
return this;
@@ -3678,7 +3750,8 @@
MaybeObject* Map::SetPrototypeTransitions(FixedArray* proto_transitions) {
- MaybeObject* allow_prototype = EnsureHasTransitionArray(this);
+ MaybeObject* allow_prototype =
+ EnsureHasTransitionArray(this, FULL_TRANSITION_ARRAY);
if (allow_prototype->IsFailure()) return allow_prototype;
#ifdef DEBUG
if (HasPrototypeTransitions()) {
@@ -4884,8 +4957,7 @@
raw_running_hash_(seed),
array_index_(0),
is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize),
- is_first_char_(true),
- is_valid_(true) {
+ is_first_char_(true) {
ASSERT(FLAG_randomize_hashes || raw_running_hash_ == 0);
}
@@ -4895,6 +4967,25 @@
}
+uint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint32_t c) {
+ running_hash += c;
+ running_hash += (running_hash << 10);
+ running_hash ^= (running_hash >> 6);
+ return running_hash;
+}
+
+
+uint32_t StringHasher::GetHashCore(uint32_t running_hash) {
+ running_hash += (running_hash << 3);
+ running_hash ^= (running_hash >> 11);
+ running_hash += (running_hash << 15);
+ if ((running_hash & String::kHashBitMask) == 0) {
+ return 27;
+ }
+ return running_hash;
+}
+
+
void StringHasher::AddCharacter(uint32_t c) {
if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) {
AddSurrogatePair(c); // Not inlined.
@@ -4902,9 +4993,7 @@
}
// Use the Jenkins one-at-a-time hash function to update the hash
// for the given character.
- raw_running_hash_ += c;
- raw_running_hash_ += (raw_running_hash_ << 10);
- raw_running_hash_ ^= (raw_running_hash_ >> 6);
+ raw_running_hash_ = AddCharacterCore(raw_running_hash_, c);
// Incremental array index computation.
if (is_array_index_) {
if (c < '0' || c > '9') {
@@ -4934,23 +5023,14 @@
AddSurrogatePairNoIndex(c); // Not inlined.
return;
}
- raw_running_hash_ += c;
- raw_running_hash_ += (raw_running_hash_ << 10);
- raw_running_hash_ ^= (raw_running_hash_ >> 6);
+ raw_running_hash_ = AddCharacterCore(raw_running_hash_, c);
}
uint32_t StringHasher::GetHash() {
// Get the calculated raw hash value and do some more bit ops to distribute
// the hash further. Ensure that we never return zero as the hash value.
- uint32_t result = raw_running_hash_;
- result += (result << 3);
- result ^= (result >> 11);
- result += (result << 15);
- if ((result & String::kHashBitMask) == 0) {
- result = 27;
- }
- return result;
+ return GetHashCore(raw_running_hash_);
}
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index fc0d7be..d7727c1 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -562,7 +562,12 @@
if (is_access_check_needed()) {
PrintF(out, " - access_check_needed\n");
}
- PrintF(out, " - instance descriptors: ");
+ PrintF(out, " - back pointer: ");
+ GetBackPointer()->ShortPrint(out);
+ PrintF(out, "\n - instance descriptors %i #%i %i: ",
+ owns_descriptors(),
+ NumberOfOwnDescriptors(),
+ StoresOwnDescriptors());
instance_descriptors()->ShortPrint(out);
if (HasTransitionArray()) {
PrintF(out, "\n - transitions: ");
diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h
index 856ae06..5d33e2e 100644
--- a/src/objects-visiting-inl.h
+++ b/src/objects-visiting-inl.h
@@ -134,12 +134,9 @@
Oddball::BodyDescriptor,
void>::Visit);
- table_.Register(kVisitMap,
- &FixedBodyVisitor<StaticVisitor,
- Map::BodyDescriptor,
- void>::Visit);
+ table_.Register(kVisitMap, &VisitMap);
- table_.Register(kVisitCode, &StaticVisitor::VisitCode);
+ table_.Register(kVisitCode, &VisitCode);
// Registration for kVisitSharedFunctionInfo is done by StaticVisitor.
@@ -247,6 +244,32 @@
template<typename StaticVisitor>
+void StaticMarkingVisitor<StaticVisitor>::VisitMap(
+ Map* map, HeapObject* object) {
+ Heap* heap = map->GetHeap();
+ Map* map_object = Map::cast(object);
+
+ // Clears the cache of ICs related to this map.
+ if (FLAG_cleanup_code_caches_at_gc) {
+ map_object->ClearCodeCache(heap);
+ }
+
+ // When map collection is enabled we have to mark through map's
+ // transitions and back pointers in a special way to make these links
+ // weak. Only maps for subclasses of JSReceiver can have transitions.
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
+ if (FLAG_collect_maps &&
+ map_object->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
+ MarkMapContents(heap, map_object);
+ } else {
+ StaticVisitor::VisitPointers(heap,
+ HeapObject::RawField(object, Map::kPointerFieldsBeginOffset),
+ HeapObject::RawField(object, Map::kPointerFieldsEndOffset));
+ }
+}
+
+
+template<typename StaticVisitor>
void StaticMarkingVisitor<StaticVisitor>::VisitCode(
Map* map, HeapObject* object) {
Heap* heap = map->GetHeap();
@@ -269,6 +292,63 @@
}
+template<typename StaticVisitor>
+void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(
+ Heap* heap, Map* map) {
+ // Make sure that the back pointer stored either in the map itself or
+ // inside its transitions array is marked. Skip recording the back
+ // pointer slot since map space is not compacted.
+ StaticVisitor::MarkObject(heap, HeapObject::cast(map->GetBackPointer()));
+
+ // Treat pointers in the transitions array as weak and also mark that
+ // array to prevent visiting it later. Skip recording the transition
+ // array slot, since it will be implicitly recorded when the pointer
+ // fields of this map are visited.
+ TransitionArray* transitions = map->unchecked_transition_array();
+ if (transitions->IsTransitionArray()) {
+ MarkTransitionArray(heap, transitions);
+ } else {
+ // Already marked by marking map->GetBackPointer() above.
+ ASSERT(transitions->IsMap() || transitions->IsUndefined());
+ }
+
+ // Mark the pointer fields of the Map. Since the transitions array has
+ // been marked already, it is fine that one of these fields contains a
+ // pointer to it.
+ StaticVisitor::VisitPointers(heap,
+ HeapObject::RawField(map, Map::kPointerFieldsBeginOffset),
+ HeapObject::RawField(map, Map::kPointerFieldsEndOffset));
+}
+
+
+template<typename StaticVisitor>
+void StaticMarkingVisitor<StaticVisitor>::MarkTransitionArray(
+ Heap* heap, TransitionArray* transitions) {
+ if (!StaticVisitor::MarkObjectWithoutPush(heap, transitions)) return;
+
+ // Skip recording the descriptors_pointer slot since the cell space
+ // is not compacted and descriptors are referenced through a cell.
+ StaticVisitor::MarkObject(heap, transitions->descriptors_pointer());
+
+ // Simple transitions do not have keys nor prototype transitions.
+ if (transitions->IsSimpleTransition()) return;
+
+ if (transitions->HasPrototypeTransitions()) {
+ // Mark prototype transitions array but do not push it onto marking
+ // stack, this will make references from it weak. We will clean dead
+ // prototype transitions in ClearNonLiveTransitions.
+ Object** slot = transitions->GetPrototypeTransitionsSlot();
+ HeapObject* obj = HeapObject::cast(*slot);
+ heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
+ StaticVisitor::MarkObjectWithoutPush(heap, obj);
+ }
+
+ for (int i = 0; i < transitions->number_of_transitions(); ++i) {
+ StaticVisitor::VisitPointer(heap, transitions->GetKeySlot(i));
+ }
+}
+
+
void Code::CodeIterateBody(ObjectVisitor* v) {
int mode_mask = RelocInfo::kCodeTargetMask |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
diff --git a/src/objects-visiting.h b/src/objects-visiting.h
index 76a0f74..7a3b3f4 100644
--- a/src/objects-visiting.h
+++ b/src/objects-visiting.h
@@ -398,9 +398,15 @@
static inline void VisitNativeContext(Map* map, HeapObject* object);
protected:
+ static inline void VisitMap(Map* map, HeapObject* object);
static inline void VisitCode(Map* map, HeapObject* object);
static inline void VisitJSRegExp(Map* map, HeapObject* object);
+ // Mark pointers in a Map and its TransitionArray together, possibly
+ // treating transitions or back pointers weak.
+ static void MarkMapContents(Heap* heap, Map* map);
+ static void MarkTransitionArray(Heap* heap, TransitionArray* transitions);
+
class DataObjectVisitor {
public:
template<int size>
diff --git a/src/objects.cc b/src/objects.cc
index 2206e64..4d8fe8e 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -651,11 +651,9 @@
receiver, result->GetCallbackObject(), name);
case HANDLER:
return result->proxy()->GetPropertyWithHandler(receiver, name);
- case INTERCEPTOR: {
- JSObject* recvr = JSObject::cast(receiver);
+ case INTERCEPTOR:
return result->holder()->GetPropertyWithInterceptor(
- recvr, name, attributes);
- }
+ receiver, name, attributes);
case TRANSITION:
case NONEXISTENT:
UNREACHABLE();
@@ -1692,7 +1690,7 @@
}
if (HasFastProperties()) {
// Ensure the descriptor array does not get too big.
- if (map_of_this->instance_descriptors()->number_of_descriptors() <
+ if (map_of_this->NumberOfOwnDescriptors() <
DescriptorArray::kMaxNumberOfDescriptors) {
if (value->IsJSFunction()) {
return AddConstantFunctionProperty(name,
@@ -2162,11 +2160,13 @@
static void ZapEndOfFixedArray(Address new_end, int to_trim) {
// If we are doing a big trim in old space then we zap the space.
Object** zap = reinterpret_cast<Object**>(new_end);
+ zap++; // Header of filler must be at least one word so skip that.
for (int i = 1; i < to_trim; i++) {
*zap++ = Smi::FromInt(0);
}
}
+
template<RightTrimMode trim_mode>
static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
ASSERT(elms->map() != HEAP->fixed_cow_array_map());
@@ -2207,14 +2207,31 @@
}
-void Map::CopyAppendCallbackDescriptors(Handle<Map> map,
- Handle<Object> descriptors) {
+void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
+ Handle<DescriptorArray> descriptors(map->instance_descriptors());
+ if (slack <= descriptors->NumberOfSlackDescriptors()) return;
+ int number_of_descriptors = descriptors->number_of_descriptors();
+ Isolate* isolate = map->GetIsolate();
+ Handle<DescriptorArray> new_descriptors =
+ isolate->factory()->NewDescriptorArray(number_of_descriptors, slack);
+ DescriptorArray::WhitenessWitness witness(*new_descriptors);
+
+ for (int i = 0; i < number_of_descriptors; ++i) {
+ new_descriptors->CopyFrom(i, *descriptors, i, witness);
+ }
+
+ Map::SetDescriptors(map, new_descriptors);
+}
+
+
+void Map::AppendCallbackDescriptors(Handle<Map> map,
+ Handle<Object> descriptors) {
Isolate* isolate = map->GetIsolate();
Handle<DescriptorArray> array(map->instance_descriptors());
- v8::NeanderArray callbacks(descriptors);
+ NeanderArray callbacks(descriptors);
int nof_callbacks = callbacks.length();
- int descriptor_count = array->number_of_descriptors();
- ASSERT(descriptor_count == map->NumberOfOwnDescriptors());
+
+ ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks);
// Ensure the keys are symbols before writing them into the instance
// descriptor. Since it may cause a GC, it has to be done before we
@@ -2227,51 +2244,23 @@
entry->set_name(*key);
}
- Handle<DescriptorArray> result =
- isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks);
-
- // Ensure that marking will not progress and change color of objects.
- DescriptorArray::WhitenessWitness witness(*result);
-
- // Copy the descriptors from the array.
- for (int i = 0; i < descriptor_count; i++) {
- result->CopyFrom(i, *array, i, witness);
- }
-
- // After this point the GC is not allowed to run anymore until the map is in a
- // consistent state again, i.e., all the descriptors are appended and the
- // descriptor array is trimmed to the right size.
- Map::SetDescriptors(map, result);
+ int nof = map->NumberOfOwnDescriptors();
// Fill in new callback descriptors. Process the callbacks from
// back to front so that the last callback with a given name takes
// precedence over previously added callbacks with that name.
- int nof = descriptor_count;
for (int i = nof_callbacks - 1; i >= 0; i--) {
AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i));
String* key = String::cast(entry->name());
// Check if a descriptor with this name already exists before writing.
- if (result->Search(key, nof) == DescriptorArray::kNotFound) {
+ if (array->Search(key, nof) == DescriptorArray::kNotFound) {
CallbacksDescriptor desc(key, entry, entry->property_attributes());
- map->AppendDescriptor(&desc, witness);
+ array->Append(&desc);
nof += 1;
}
}
- ASSERT(nof == map->NumberOfOwnDescriptors());
-
- // Reinstall the original descriptor array if no new elements were added.
- if (nof == descriptor_count) {
- Map::SetDescriptors(map, array);
- return;
- }
-
- // If duplicates were detected, trim the descriptor array to the right size.
- int new_array_size = DescriptorArray::LengthFor(nof);
- if (new_array_size < result->length()) {
- RightTrimFixedArray<FROM_MUTATOR>(
- isolate->heap(), *result, result->length() - new_array_size);
- }
+ map->SetNumberOfOwnDescriptors(nof);
}
@@ -3335,8 +3324,7 @@
// Allocate new content.
int real_size = map_of_this->NumberOfOwnDescriptors();
- int property_count =
- map_of_this->NumberOfDescribedProperties(OWN_DESCRIPTORS);
+ int property_count = real_size;
if (expected_additional_properties > 0) {
property_count += expected_additional_properties;
} else {
@@ -5003,32 +4991,45 @@
String* name = descriptor->GetKey();
TransitionArray* transitions;
- MaybeObject* maybe_transitions = AddTransition(name, result);
+ MaybeObject* maybe_transitions =
+ AddTransition(name, result, SIMPLE_TRANSITION);
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
DescriptorArray* descriptors = instance_descriptors();
int old_size = descriptors->number_of_descriptors();
DescriptorArray* new_descriptors;
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size + 1);
- if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
- DescriptorArray::WhitenessWitness witness(new_descriptors);
- for (int i = 0; i < old_size; ++i) {
- new_descriptors->CopyFrom(i, descriptors, i, witness);
- }
- new_descriptors->Append(descriptor, witness, old_size);
+ if (descriptors->NumberOfSlackDescriptors() > 0) {
+ new_descriptors = descriptors;
+ new_descriptors->Append(descriptor);
+ } else {
+ // Descriptor arrays grow by 50%.
+ MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
+ old_size, old_size < 4 ? 1 : old_size / 2);
+ if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
- // If the source descriptors had an enum cache we copy it. This ensures that
- // the maps to which we push the new descriptor array back can rely on a
- // cache always being available once it is set. If the map has more
- // enumerated descriptors than available in the original cache, the cache
- // will be lazily replaced by the extended cache when needed.
- if (descriptors->HasEnumCache()) {
- new_descriptors->CopyEnumCacheFrom(descriptors);
+ DescriptorArray::WhitenessWitness witness(new_descriptors);
+
+ // Copy the descriptors, inserting a descriptor.
+ for (int i = 0; i < old_size; ++i) {
+ new_descriptors->CopyFrom(i, descriptors, i, witness);
+ }
+
+ new_descriptors->Append(descriptor, witness);
+
+ // If the source descriptors had an enum cache we copy it. This ensures that
+ // the maps to which we push the new descriptor array back can rely on a
+ // cache always being available once it is set. If the map has more
+ // enumerated descriptors than available in the original cache, the cache
+ // will be lazily replaced by the extended cache when needed.
+ if (descriptors->HasEnumCache()) {
+ new_descriptors->CopyEnumCacheFrom(descriptors);
+ }
}
transitions->set_descriptors(new_descriptors);
+
set_transitions(transitions);
result->SetBackPointer(this);
set_owns_descriptors(false);
@@ -5042,7 +5043,8 @@
MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
String* name,
- TransitionFlag flag) {
+ TransitionFlag flag,
+ int descriptor_index) {
ASSERT(descriptors->IsSortedNoDuplicates());
Map* result;
@@ -5059,7 +5061,11 @@
if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) {
TransitionArray* transitions;
- MaybeObject* maybe_transitions = AddTransition(name, result);
+ SimpleTransitionFlag simple_flag =
+ (descriptor_index == descriptors->number_of_descriptors() - 1)
+ ? SIMPLE_TRANSITION
+ : FULL_TRANSITION;
+ MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag);
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
if (descriptors->IsEmpty()) {
@@ -5126,7 +5132,7 @@
ASSERT(new_map->NumberOfOwnDescriptors() == NumberOfOwnDescriptors());
new_map->set_elements_kind(kind);
- if (flag == INSERT_TRANSITION) {
+ if (flag == INSERT_TRANSITION && !HasElementsTransition()) {
// Map::Copy does not store the descriptor array in case it is empty, since
// it does not insert a back pointer; implicitly indicating that its
// descriptor array is empty. Since in this case we do want to insert a back
@@ -5164,7 +5170,7 @@
descriptors->CopyUpTo(number_of_own_descriptors);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
- return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION);
+ return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0);
}
@@ -5176,7 +5182,7 @@
descriptors->CopyUpTo(number_of_own_descriptors);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
- return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION);
+ return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0);
}
@@ -5199,7 +5205,7 @@
}
DescriptorArray* new_descriptors;
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size + 1);
+ MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(new_descriptors);
@@ -5209,10 +5215,18 @@
new_descriptors->CopyFrom(i, descriptors, i, witness);
}
- new_descriptors->Set(old_size, descriptor, witness);
- new_descriptors->Sort();
+ if (old_size != descriptors->number_of_descriptors()) {
+ new_descriptors->SetNumberOfDescriptors(new_size);
+ new_descriptors->Set(old_size, descriptor, witness);
+ new_descriptors->Sort();
+ } else {
+ new_descriptors->Append(descriptor, witness);
+ }
- return CopyReplaceDescriptors(new_descriptors, descriptor->GetKey(), flag);
+ String* key = descriptor->GetKey();
+ int insertion_index = new_descriptors->number_of_descriptors() - 1;
+
+ return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index);
}
@@ -5288,7 +5302,7 @@
// Re-sort if descriptors were removed.
if (new_size != descriptors->length()) new_descriptors->Sort();
- return CopyReplaceDescriptors(new_descriptors, key, flag);
+ return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index);
}
@@ -6063,16 +6077,17 @@
#endif
-MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
+MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) {
Heap* heap = Isolate::Current()->heap();
// Do not use DescriptorArray::cast on incomplete object.
+ int size = number_of_descriptors + slack;
+ if (size == 0) return heap->empty_descriptor_array();
FixedArray* result;
- if (number_of_descriptors == 0) return heap->empty_descriptor_array();
// Allocate the array of keys.
- MaybeObject* maybe_array =
- heap->AllocateFixedArray(LengthFor(number_of_descriptors));
+ MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size));
if (!maybe_array->To(&result)) return maybe_array;
+ result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
result->set(kEnumCacheIndex, Smi::FromInt(0));
return result;
}
@@ -6089,7 +6104,7 @@
ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
if (HasEnumCache()) {
- ASSERT(new_cache->length() > FixedArray::cast(GetEnumCache())->length());
+ ASSERT(new_cache->length() > GetEnumCache()->length());
FixedArray::cast(get(kEnumCacheIndex))->
set(kEnumCacheBridgeCacheIndex, new_cache);
FixedArray::cast(get(kEnumCacheIndex))->
@@ -7362,7 +7377,6 @@
uint32_t StringHasher::GetHashField() {
- ASSERT(is_valid());
if (length_ <= String::kMaxHashCalcLength) {
if (is_array_index()) {
return MakeArrayIndexHash(array_index(), length_);
@@ -7417,10 +7431,61 @@
}
+static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) {
+ int live_enum = map->EnumLength();
+ if (live_enum == Map::kInvalidEnumCache) {
+ live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM);
+ }
+ if (live_enum == 0) return descriptors->ClearEnumCache();
+
+ FixedArray* enum_cache = descriptors->GetEnumCache();
+
+ int to_trim = enum_cache->length() - live_enum;
+ if (to_trim <= 0) return;
+ RightTrimFixedArray<FROM_GC>(heap, descriptors->GetEnumCache(), to_trim);
+
+ if (!descriptors->HasEnumIndicesCache()) return;
+ FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache();
+ RightTrimFixedArray<FROM_GC>(heap, enum_indices_cache, to_trim);
+}
+
+
+static void TrimDescriptorArray(Heap* heap,
+ Map* map,
+ DescriptorArray* descriptors,
+ int number_of_own_descriptors) {
+ int number_of_descriptors = descriptors->number_of_descriptors();
+ int to_trim = number_of_descriptors - number_of_own_descriptors;
+ if (to_trim <= 0) return;
+
+ // Maximally keep 50% of unused descriptors.
+ int keep = Min(to_trim, number_of_own_descriptors / 2);
+ for (int i = number_of_own_descriptors;
+ i < number_of_own_descriptors + keep;
+ ++i) {
+ descriptors->EraseDescriptor(heap, i);
+ }
+
+ if (to_trim > keep) {
+ RightTrimFixedArray<FROM_GC>(heap, descriptors, to_trim - keep);
+ }
+ descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
+
+ if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors);
+ descriptors->Sort();
+}
+
+
// Clear a possible back pointer in case the transition leads to a dead map.
// Return true in case a back pointer has been cleared and false otherwise.
-static bool ClearBackPointer(Heap* heap, Map* target) {
+static bool ClearBackPointer(Heap* heap,
+ Map* target,
+ DescriptorArray* descriptors,
+ bool* descriptors_owner_died) {
if (Marking::MarkBitFrom(target).Get()) return false;
+ if (target->instance_descriptors() == descriptors) {
+ *descriptors_owner_died = true;
+ }
target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
return true;
}
@@ -7446,15 +7511,7 @@
// Compact all live descriptors to the left.
for (int i = 0; i < t->number_of_transitions(); ++i) {
Map* target = t->GetTarget(i);
- if (ClearBackPointer(heap, target)) {
- ASSERT(!Marking::IsGrey(Marking::MarkBitFrom(target)));
- DescriptorArray* target_descriptors = target->instance_descriptors();
- if ((target_descriptors->number_of_descriptors() == 0 &&
- target->NumberOfOwnDescriptors() > 0) ||
- target_descriptors == descriptors) {
- descriptors_owner_died = true;
- }
- } else {
+ if (!ClearBackPointer(heap, target, descriptors, &descriptors_owner_died)) {
if (i != transition_index) {
String* key = t->GetKey(i);
t->SetKey(transition_index, key);
@@ -7468,10 +7525,10 @@
}
if (t->HasElementsTransition() &&
- ClearBackPointer(heap, t->elements_transition())) {
- if (t->elements_transition()->instance_descriptors() == descriptors) {
- descriptors_owner_died = true;
- }
+ ClearBackPointer(heap,
+ t->elements_transition(),
+ descriptors,
+ &descriptors_owner_died)) {
t->ClearElementsTransition();
} else {
// If there are no transitions to be cleared, return.
@@ -7484,28 +7541,7 @@
if (descriptors_owner_died) {
if (number_of_own_descriptors > 0) {
- int number_of_descriptors = descriptors->number_of_descriptors();
- int to_trim = number_of_descriptors - number_of_own_descriptors;
- if (to_trim > 0) {
- RightTrimFixedArray<FROM_GC>(
- heap, descriptors, to_trim * DescriptorArray::kDescriptorSize);
- if (descriptors->HasEnumCache()) {
- int live_enum =
- NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM);
- if (live_enum == 0) {
- descriptors->ClearEnumCache();
- } else {
- FixedArray* enum_cache =
- FixedArray::cast(descriptors->GetEnumCache());
- to_trim = enum_cache->length() - live_enum;
- if (to_trim > 0) {
- RightTrimFixedArray<FROM_GC>(
- heap, FixedArray::cast(descriptors->GetEnumCache()), to_trim);
- }
- }
- }
- descriptors->Sort();
- }
+ TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors);
ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
} else {
t->set_descriptors(heap->empty_descriptor_array());
@@ -7513,20 +7549,10 @@
set_owns_descriptors(true);
}
- // If the final transition array does not contain any live transitions, remove
- // the transition array from the map.
- if (transition_index == 0 &&
- !t->HasElementsTransition() &&
- !t->HasPrototypeTransitions() &&
- number_of_own_descriptors == 0) {
- ASSERT(owns_descriptors());
- return ClearTransitions(heap);
- }
-
int trim = t->number_of_transitions() - transition_index;
if (trim > 0) {
- RightTrimFixedArray<FROM_GC>(
- heap, t, trim * TransitionArray::kTransitionSize);
+ RightTrimFixedArray<FROM_GC>(heap, t, t->IsSimpleTransition()
+ ? trim : trim * TransitionArray::kTransitionSize);
}
}
@@ -10473,7 +10499,7 @@
MaybeObject* JSObject::GetPropertyPostInterceptor(
- JSReceiver* receiver,
+ Object* receiver,
String* name,
PropertyAttributes* attributes) {
// Check local property in holder, ignore interceptor.
@@ -10491,7 +10517,7 @@
MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
- JSReceiver* receiver,
+ Object* receiver,
String* name,
PropertyAttributes* attributes) {
// Check local property in holder, ignore interceptor.
@@ -10505,13 +10531,13 @@
MaybeObject* JSObject::GetPropertyWithInterceptor(
- JSReceiver* receiver,
+ Object* receiver,
String* name,
PropertyAttributes* attributes) {
Isolate* isolate = GetIsolate();
InterceptorInfo* interceptor = GetNamedInterceptor();
HandleScope scope(isolate);
- Handle<JSReceiver> receiver_handle(receiver);
+ Handle<Object> receiver_handle(receiver);
Handle<JSObject> holder_handle(this);
Handle<String> name_handle(name);
@@ -10643,9 +10669,16 @@
int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
- return HasFastProperties() ?
- map()->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter) :
- property_dictionary()->NumberOfElementsFilterAttributes(filter);
+ if (HasFastProperties()) {
+ Map* map = this->map();
+ if (filter == NONE) return map->NumberOfOwnDescriptors();
+ if (filter == DONT_ENUM) {
+ int result = map->EnumLength();
+ if (result != Map::kInvalidEnumCache) return result;
+ }
+ return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
+ }
+ return property_dictionary()->NumberOfElementsFilterAttributes(filter);
}
diff --git a/src/objects.h b/src/objects.h
index c222086..14f81f8 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -177,6 +177,16 @@
OMIT_TRANSITION
};
+
+// Indicates whether the transition is simple: the target map of the transition
+// either extends the current map with a new property, or it modifies the
+// property that was added last to the current map.
+enum SimpleTransitionFlag {
+ SIMPLE_TRANSITION,
+ FULL_TRANSITION
+};
+
+
// Indicates whether we are only interested in the descriptors of a particular
// map, or in all descriptors in the descriptor array.
enum DescriptorFlag {
@@ -1687,15 +1697,15 @@
String* name,
PropertyAttributes* attributes);
MUST_USE_RESULT MaybeObject* GetPropertyWithInterceptor(
- JSReceiver* receiver,
+ Object* receiver,
String* name,
PropertyAttributes* attributes);
MUST_USE_RESULT MaybeObject* GetPropertyPostInterceptor(
- JSReceiver* receiver,
+ Object* receiver,
String* name,
PropertyAttributes* attributes);
MUST_USE_RESULT MaybeObject* GetLocalPropertyPostInterceptor(
- JSReceiver* receiver,
+ Object* receiver,
String* name,
PropertyAttributes* attributes);
@@ -2484,9 +2494,19 @@
int number_of_descriptors() {
ASSERT(length() >= kFirstIndex || IsEmpty());
int len = length();
- return len <= kFirstIndex ? 0 : (len - kFirstIndex) / kDescriptorSize;
+ return len == 0 ? 0 : Smi::cast(get(kDescriptorLengthIndex))->value();
}
+ int number_of_descriptors_storage() {
+ int len = length();
+ return len == 0 ? 0 : (len - kFirstIndex) / kDescriptorSize;
+ }
+
+ int NumberOfSlackDescriptors() {
+ return number_of_descriptors_storage() - number_of_descriptors();
+ }
+
+ inline void SetNumberOfDescriptors(int number_of_descriptors);
inline int number_of_entries() { return number_of_descriptors(); }
bool HasEnumCache() {
@@ -2497,10 +2517,24 @@
set(kEnumCacheIndex, array->get(kEnumCacheIndex));
}
- Object* GetEnumCache() {
+ FixedArray* GetEnumCache() {
ASSERT(HasEnumCache());
FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex));
- return bridge->get(kEnumCacheBridgeCacheIndex);
+ return FixedArray::cast(bridge->get(kEnumCacheBridgeCacheIndex));
+ }
+
+ bool HasEnumIndicesCache() {
+ if (IsEmpty()) return false;
+ Object* object = get(kEnumCacheIndex);
+ if (object->IsSmi()) return false;
+ FixedArray* bridge = FixedArray::cast(object);
+ return !bridge->get(kEnumCacheBridgeIndicesCacheIndex)->IsSmi();
+ }
+
+ FixedArray* GetEnumIndicesCache() {
+ ASSERT(HasEnumIndicesCache());
+ FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex));
+ return FixedArray::cast(bridge->get(kEnumCacheBridgeIndicesCacheIndex));
}
Object** GetEnumCacheSlot() {
@@ -2538,13 +2572,14 @@
inline void Set(int descriptor_number,
Descriptor* desc,
const WhitenessWitness&);
+ inline void Set(int descriptor_number, Descriptor* desc);
+ inline void EraseDescriptor(Heap* heap, int descriptor_number);
// Append automatically sets the enumeration index. This should only be used
// to add descriptors in bulk at the end, followed by sorting the descriptor
// array.
- inline void Append(Descriptor* desc,
- const WhitenessWitness&,
- int number_of_set_descriptors);
+ inline void Append(Descriptor* desc, const WhitenessWitness&);
+ inline void Append(Descriptor* desc);
// Transfer a complete descriptor from the src descriptor array to this
// descriptor array.
@@ -2567,7 +2602,8 @@
// Allocates a DescriptorArray, but returns the singleton
// empty descriptor array object if number_of_descriptors is 0.
- MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors);
+ MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors,
+ int slack = 0);
// Casting.
static inline DescriptorArray* cast(Object* obj);
@@ -2575,8 +2611,9 @@
// Constant for denoting key was not found.
static const int kNotFound = -1;
- static const int kEnumCacheIndex = 0;
- static const int kFirstIndex = 1;
+ static const int kDescriptorLengthIndex = 0;
+ static const int kEnumCacheIndex = 1;
+ static const int kFirstIndex = 2;
// The length of the "bridge" to the enum cache.
static const int kEnumCacheBridgeLength = 2;
@@ -2584,7 +2621,8 @@
static const int kEnumCacheBridgeIndicesCacheIndex = 1;
// Layout description.
- static const int kEnumCacheOffset = FixedArray::kHeaderSize;
+ static const int kDescriptorLengthOffset = FixedArray::kHeaderSize;
+ static const int kEnumCacheOffset = kDescriptorLengthOffset + kPointerSize;
static const int kFirstOffset = kEnumCacheOffset + kPointerSize;
// Layout description for the bridge array.
@@ -2875,11 +2913,12 @@
return (hash + GetProbeOffset(number)) & (size - 1);
}
- static uint32_t FirstProbe(uint32_t hash, uint32_t size) {
+ inline static uint32_t FirstProbe(uint32_t hash, uint32_t size) {
return hash & (size - 1);
}
- static uint32_t NextProbe(uint32_t last, uint32_t number, uint32_t size) {
+ inline static uint32_t NextProbe(
+ uint32_t last, uint32_t number, uint32_t size) {
return (last + number) & (size - 1);
}
@@ -2966,6 +3005,8 @@
private:
MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s);
+ template <bool seq_ascii> friend class JsonParser;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable);
};
@@ -4808,7 +4849,9 @@
Map* transitioned_map);
inline void SetTransition(int transition_index, Map* target);
inline Map* GetTransition(int transition_index);
- MUST_USE_RESULT inline MaybeObject* AddTransition(String* key, Map* target);
+ MUST_USE_RESULT inline MaybeObject* AddTransition(String* key,
+ Map* target,
+ SimpleTransitionFlag flag);
DECL_ACCESSORS(transitions, TransitionArray)
inline void ClearTransitions(Heap* heap,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
@@ -4959,7 +5002,8 @@
MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors(
DescriptorArray* descriptors,
String* name,
- TransitionFlag flag);
+ TransitionFlag flag,
+ int descriptor_index);
MUST_USE_RESULT MaybeObject* ShareDescriptor(Descriptor* descriptor);
MUST_USE_RESULT MaybeObject* CopyAddDescriptor(Descriptor* descriptor,
TransitionFlag flag);
@@ -5011,8 +5055,10 @@
// Extend the descriptor array of the map with the list of descriptors.
// In case of duplicates, the latest descriptor is used.
- static void CopyAppendCallbackDescriptors(Handle<Map> map,
- Handle<Object> descriptors);
+ static void AppendCallbackDescriptors(Handle<Map> map,
+ Handle<Object> descriptors);
+
+ static void EnsureDescriptorSlack(Handle<Map> map, int slack);
// Returns the found code or undefined if absent.
Object* FindInCodeCache(String* name, Code::Flags flags);
@@ -7011,10 +7057,6 @@
// index.
bool is_array_index() { return is_array_index_; }
- bool is_valid() { return is_valid_; }
-
- void invalidate() { is_valid_ = false; }
-
// Calculated hash value for a string consisting of 1 to
// String::kMaxArrayIndexSize digits with no leading zeros (except "0").
// value is represented decimal value.
@@ -7033,13 +7075,33 @@
inline uint32_t GetHash();
+ // Reusable parts of the hashing algorithm.
+ INLINE(static uint32_t AddCharacterCore(uint32_t running_hash, uint32_t c));
+ INLINE(static uint32_t GetHashCore(uint32_t running_hash));
+
int length_;
uint32_t raw_running_hash_;
uint32_t array_index_;
bool is_array_index_;
bool is_first_char_;
- bool is_valid_;
friend class TwoCharHashTableKey;
+
+ template <bool seq_ascii> friend class JsonParser;
+};
+
+
+class IncrementalAsciiStringHasher {
+ public:
+ explicit inline IncrementalAsciiStringHasher(uint32_t seed, char first_char);
+ inline void AddCharacter(uc32 c);
+ inline uint32_t GetHash();
+
+ private:
+ int length_;
+ uint32_t raw_running_hash_;
+ uint32_t array_index_;
+ bool is_array_index_;
+ char first_char_;
};
diff --git a/src/parser.cc b/src/parser.cc
index 37e903a..129bd95 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -642,7 +642,7 @@
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
bool ok = true;
int beg_loc = scanner().location().beg_pos;
- ParseSourceElements(body, Token::EOS, info->is_eval(), &ok);
+ ParseSourceElements(body, Token::EOS, info->is_eval(), true, &ok);
if (ok && !top_scope_->is_classic_mode()) {
CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
}
@@ -832,145 +832,10 @@
}
-// Base class containing common code for the different finder classes used by
-// the parser.
-class ParserFinder {
- protected:
- ParserFinder() {}
- static Assignment* AsAssignment(Statement* stat) {
- if (stat == NULL) return NULL;
- ExpressionStatement* exp_stat = stat->AsExpressionStatement();
- if (exp_stat == NULL) return NULL;
- return exp_stat->expression()->AsAssignment();
- }
-};
-
-
-// An InitializationBlockFinder finds and marks sequences of statements of the
-// form expr.a = ...; expr.b = ...; etc.
-class InitializationBlockFinder : public ParserFinder {
- public:
- // We find and mark the initialization blocks in top level
- // non-looping code only. This is because the optimization prevents
- // reuse of the map transitions, so it should be used only for code
- // that will only be run once.
- InitializationBlockFinder(Scope* top_scope, Target* target)
- : enabled_(top_scope->DeclarationScope()->is_global_scope() &&
- !IsLoopTarget(target)),
- first_in_block_(NULL),
- last_in_block_(NULL),
- block_size_(0) {}
-
- ~InitializationBlockFinder() {
- if (!enabled_) return;
- if (InBlock()) EndBlock();
- }
-
- void Update(Statement* stat) {
- if (!enabled_) return;
- Assignment* assignment = AsAssignment(stat);
- if (InBlock()) {
- if (BlockContinues(assignment)) {
- UpdateBlock(assignment);
- } else {
- EndBlock();
- }
- }
- if (!InBlock() && (assignment != NULL) &&
- (assignment->op() == Token::ASSIGN)) {
- StartBlock(assignment);
- }
- }
-
- private:
- // The minimum number of contiguous assignment that will
- // be treated as an initialization block. Benchmarks show that
- // the overhead exceeds the savings below this limit.
- static const int kMinInitializationBlock = 3;
-
- static bool IsLoopTarget(Target* target) {
- while (target != NULL) {
- if (target->node()->AsIterationStatement() != NULL) return true;
- target = target->previous();
- }
- return false;
- }
-
- // Returns true if the expressions appear to denote the same object.
- // In the context of initialization blocks, we only consider expressions
- // of the form 'expr.x' or expr["x"].
- static bool SameObject(Expression* e1, Expression* e2) {
- VariableProxy* v1 = e1->AsVariableProxy();
- VariableProxy* v2 = e2->AsVariableProxy();
- if (v1 != NULL && v2 != NULL) {
- return v1->name()->Equals(*v2->name());
- }
- Property* p1 = e1->AsProperty();
- Property* p2 = e2->AsProperty();
- if ((p1 == NULL) || (p2 == NULL)) return false;
- Literal* key1 = p1->key()->AsLiteral();
- Literal* key2 = p2->key()->AsLiteral();
- if ((key1 == NULL) || (key2 == NULL)) return false;
- if (!key1->handle()->IsString() || !key2->handle()->IsString()) {
- return false;
- }
- String* name1 = String::cast(*key1->handle());
- String* name2 = String::cast(*key2->handle());
- if (!name1->Equals(name2)) return false;
- return SameObject(p1->obj(), p2->obj());
- }
-
- // Returns true if the expressions appear to denote different properties
- // of the same object.
- static bool PropertyOfSameObject(Expression* e1, Expression* e2) {
- Property* p1 = e1->AsProperty();
- Property* p2 = e2->AsProperty();
- if ((p1 == NULL) || (p2 == NULL)) return false;
- return SameObject(p1->obj(), p2->obj());
- }
-
- bool BlockContinues(Assignment* assignment) {
- if ((assignment == NULL) || (first_in_block_ == NULL)) return false;
- if (assignment->op() != Token::ASSIGN) return false;
- return PropertyOfSameObject(first_in_block_->target(),
- assignment->target());
- }
-
- void StartBlock(Assignment* assignment) {
- first_in_block_ = assignment;
- last_in_block_ = assignment;
- block_size_ = 1;
- }
-
- void UpdateBlock(Assignment* assignment) {
- last_in_block_ = assignment;
- ++block_size_;
- }
-
- void EndBlock() {
- if (block_size_ >= kMinInitializationBlock) {
- first_in_block_->mark_block_start();
- last_in_block_->mark_block_end();
- }
- last_in_block_ = first_in_block_ = NULL;
- block_size_ = 0;
- }
-
- bool InBlock() { return first_in_block_ != NULL; }
-
- const bool enabled_;
- Assignment* first_in_block_;
- Assignment* last_in_block_;
- int block_size_;
-
- DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder);
-};
-
-
// A ThisNamedPropertyAssignmentFinder finds and marks statements of the form
// this.x = ...;, where x is a named property. It also determines whether a
// function contains only assignments of this type.
-class ThisNamedPropertyAssignmentFinder : public ParserFinder {
+class ThisNamedPropertyAssignmentFinder {
public:
ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone)
: isolate_(isolate),
@@ -981,6 +846,13 @@
zone_(zone) {
}
+ static Assignment* AsAssignment(Statement* stat) {
+ if (stat == NULL) return NULL;
+ ExpressionStatement* exp_stat = stat->AsExpressionStatement();
+ if (exp_stat == NULL) return NULL;
+ return exp_stat->expression()->AsAssignment();
+ }
+
void Update(Scope* scope, Statement* stat) {
// Bail out if function already has property assignment that are
// not simple this property assignments.
@@ -1135,6 +1007,7 @@
void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
int end_token,
bool is_eval,
+ bool is_global,
bool* ok) {
// SourceElements ::
// (ModuleElement)* <end_token>
@@ -1146,7 +1019,6 @@
TargetScope scope(&this->target_stack_);
ASSERT(processor != NULL);
- InitializationBlockFinder block_finder(top_scope_, target_stack_);
ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(),
zone());
bool directive_prologue = true; // Parsing directive prologue.
@@ -1157,7 +1029,12 @@
}
Scanner::Location token_loc = scanner().peek_location();
- Statement* stat = ParseModuleElement(NULL, CHECK_OK);
+ Statement* stat;
+ if (is_global && !is_eval) {
+ stat = ParseModuleElement(NULL, CHECK_OK);
+ } else {
+ stat = ParseBlockElement(NULL, CHECK_OK);
+ }
if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue.
continue;
@@ -1201,7 +1078,6 @@
}
}
- block_finder.Update(stat);
// Find and mark all assignments to named properties in this (this.x =)
if (top_scope_->is_function_scope()) {
this_property_assignment_finder.Update(top_scope_, stat);
@@ -1354,13 +1230,11 @@
TargetCollector collector(zone());
Target target(&this->target_stack_, &collector);
Target target_body(&this->target_stack_, body);
- InitializationBlockFinder block_finder(top_scope_, target_stack_);
while (peek() != Token::RBRACE) {
Statement* stat = ParseModuleElement(NULL, CHECK_OK);
if (stat && !stat->IsEmpty()) {
body->AddStatement(stat, zone());
- block_finder.Update(stat);
}
}
}
@@ -2036,12 +1910,10 @@
Block* result = factory()->NewBlock(labels, 16, false);
Target target(&this->target_stack_, result);
Expect(Token::LBRACE, CHECK_OK);
- InitializationBlockFinder block_finder(top_scope_, target_stack_);
while (peek() != Token::RBRACE) {
Statement* stat = ParseStatement(NULL, CHECK_OK);
if (stat && !stat->IsEmpty()) {
result->AddStatement(stat, zone());
- block_finder.Update(stat);
}
}
Expect(Token::RBRACE, CHECK_OK);
@@ -2066,13 +1938,11 @@
TargetCollector collector(zone());
Target target(&this->target_stack_, &collector);
Target target_body(&this->target_stack_, body);
- InitializationBlockFinder block_finder(top_scope_, target_stack_);
while (peek() != Token::RBRACE) {
Statement* stat = ParseBlockElement(NULL, CHECK_OK);
if (stat && !stat->IsEmpty()) {
body->AddStatement(stat, zone());
- block_finder.Update(stat);
}
}
}
@@ -2926,8 +2796,6 @@
if (peek() == Token::IN && !name.is_null()) {
Interface* interface =
is_const ? Interface::NewConst() : Interface::NewValue();
- VariableProxy* each =
- top_scope_->NewUnresolved(factory(), name, interface);
ForInStatement* loop = factory()->NewForInStatement(labels);
Target target(&this->target_stack_, loop);
@@ -2935,6 +2803,8 @@
Expression* enumerable = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
+ VariableProxy* each =
+ top_scope_->NewUnresolved(factory(), name, interface);
Statement* body = ParseStatement(NULL, CHECK_OK);
loop->Initialize(each, enumerable, body);
Block* result = factory()->NewBlock(NULL, 2, false);
@@ -2972,18 +2842,24 @@
// TODO(keuchel): Move the temporary variable to the block scope, after
// implementing stack allocated block scoped variables.
- Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name);
+ Factory* heap_factory = isolate()->factory();
+ Handle<String> tempstr =
+ heap_factory->NewConsString(heap_factory->dot_for_symbol(), name);
+ Handle<String> tempname = heap_factory->LookupSymbol(tempstr);
+ Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
- Interface* interface = Interface::NewValue();
- VariableProxy* each =
- top_scope_->NewUnresolved(factory(), name, interface);
ForInStatement* loop = factory()->NewForInStatement(labels);
Target target(&this->target_stack_, loop);
+ // The expression does not see the loop variable.
Expect(Token::IN, CHECK_OK);
+ top_scope_ = saved_scope;
Expression* enumerable = ParseExpression(true, CHECK_OK);
+ top_scope_ = for_scope;
Expect(Token::RPAREN, CHECK_OK);
+ VariableProxy* each =
+ top_scope_->NewUnresolved(factory(), name, Interface::NewValue());
Statement* body = ParseStatement(NULL, CHECK_OK);
Block* body_block = factory()->NewBlock(NULL, 3, false);
Assignment* assignment = factory()->NewAssignment(
@@ -4667,7 +4543,7 @@
RelocInfo::kNoPosition)),
zone());
}
- ParseSourceElements(body, Token::RBRACE, false, CHECK_OK);
+ ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK);
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
diff --git a/src/parser.h b/src/parser.h
index 1ab7a14..46d4ec8 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -454,7 +454,7 @@
// construct a hashable id, so if more than 2^17 are allowed, this
// should be checked.
static const int kMaxNumFunctionParameters = 32766;
- static const int kMaxNumFunctionLocals = 32767;
+ static const int kMaxNumFunctionLocals = 65535;
enum Mode {
PARSE_LAZILY,
@@ -590,8 +590,8 @@
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites.
- void* ParseSourceElements(ZoneList<Statement*>* processor,
- int end_token, bool is_eval, bool* ok);
+ void* ParseSourceElements(ZoneList<Statement*>* processor, int end_token,
+ bool is_eval, bool is_global, bool* ok);
Statement* ParseModuleElement(ZoneStringList* labels, bool* ok);
Statement* ParseModuleDeclaration(ZoneStringList* names, bool* ok);
Module* ParseModule(bool* ok);
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index 089ea38..b39dfc0 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -692,9 +692,8 @@
CONTEXT context;
memset(&context, 0, sizeof(context));
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(sampler->isolate());
+ if (sample == NULL) return;
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
if (SuspendThread(profiled_thread) == kSuspendFailed) return;
@@ -714,6 +713,7 @@
sampler->SampleStack(sample);
sampler->Tick(sample);
}
+ CpuProfiler::FinishTickSampleEvent(sampler->isolate());
ResumeThread(profiled_thread);
}
@@ -768,6 +768,11 @@
}
+void Sampler::DoSample() {
+ // TODO(rogulenko): implement
+}
+
+
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 511759c..6d1bccd 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -678,9 +678,8 @@
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(isolate);
+ if (sample == NULL) return;
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
@@ -701,6 +700,7 @@
#endif
sampler->SampleStack(sample);
sampler->Tick(sample);
+ CpuProfiler::FinishTickSampleEvent(isolate);
}
@@ -884,6 +884,11 @@
}
+void Sampler::DoSample() {
+ // TODO(rogulenko): implement
+}
+
+
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 606d102..fe366c9 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -148,6 +148,9 @@
case ARMv7:
search_string = "ARMv7";
break;
+ case SUDIV:
+ search_string = "idiva";
+ break;
default:
UNREACHABLE();
}
@@ -1012,9 +1015,8 @@
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(isolate);
+ if (sample == NULL) return;
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
@@ -1049,16 +1051,74 @@
#endif // V8_HOST_ARCH_*
sampler->SampleStack(sample);
sampler->Tick(sample);
+ CpuProfiler::FinishTickSampleEvent(isolate);
}
+class CpuProfilerSignalHandler {
+ public:
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
+
+ static void InstallSignalHandler() {
+ struct sigaction sa;
+ ScopedLock lock(mutex_);
+ if (signal_handler_installed_counter_ > 0) {
+ signal_handler_installed_counter_++;
+ return;
+ }
+ sa.sa_sigaction = ProfilerSignalHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0) {
+ signal_handler_installed_counter_++;
+ }
+ }
+
+ static void RestoreSignalHandler() {
+ ScopedLock lock(mutex_);
+ if (signal_handler_installed_counter_ == 0)
+ return;
+ if (signal_handler_installed_counter_ == 1) {
+ sigaction(SIGPROF, &old_signal_handler_, 0);
+ }
+ signal_handler_installed_counter_--;
+ }
+
+ static bool signal_handler_installed() {
+ return signal_handler_installed_counter_ > 0;
+ }
+
+ private:
+ static int signal_handler_installed_counter_;
+ static struct sigaction old_signal_handler_;
+ static Mutex* mutex_;
+};
+
+
+int CpuProfilerSignalHandler::signal_handler_installed_counter_ = 0;
+struct sigaction CpuProfilerSignalHandler::old_signal_handler_;
+Mutex* CpuProfilerSignalHandler::mutex_ = NULL;
+
+
class Sampler::PlatformData : public Malloced {
public:
- PlatformData() : vm_tid_(GetThreadID()) {}
+ PlatformData()
+ : vm_tgid_(getpid()),
+ vm_tid_(GetThreadID()) {}
- int vm_tid() const { return vm_tid_; }
+ void SendProfilingSignal() {
+ if (!CpuProfilerSignalHandler::signal_handler_installed()) return;
+ // Glibc doesn't provide a wrapper for tgkill(2).
+#if defined(ANDROID)
+ syscall(__NR_tgkill, vm_tgid_, vm_tid_, SIGPROF);
+#else
+ syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF);
+#endif
+ }
private:
+ const int vm_tgid_;
const int vm_tid_;
};
@@ -1074,28 +1134,11 @@
explicit SignalSender(int interval)
: Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
- vm_tgid_(getpid()),
interval_(interval) {}
static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
static void TearDown() { delete mutex_; }
- static void InstallSignalHandler() {
- struct sigaction sa;
- sa.sa_sigaction = ProfilerSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- signal_handler_installed_ =
- (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
- }
-
- static void RestoreSignalHandler() {
- if (signal_handler_installed_) {
- sigaction(SIGPROF, &old_signal_handler_, 0);
- signal_handler_installed_ = false;
- }
- }
-
static void AddActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
SamplerRegistry::AddActiveSampler(sampler);
@@ -1116,7 +1159,6 @@
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
delete instance_;
instance_ = NULL;
- RestoreSignalHandler();
}
}
@@ -1125,67 +1167,21 @@
SamplerRegistry::State state;
while ((state = SamplerRegistry::GetState()) !=
SamplerRegistry::HAS_NO_SAMPLERS) {
- bool cpu_profiling_enabled =
- (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
- bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
- if (cpu_profiling_enabled && !signal_handler_installed_) {
- InstallSignalHandler();
- } else if (!cpu_profiling_enabled && signal_handler_installed_) {
- RestoreSignalHandler();
- }
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (!cpu_profiling_enabled) {
- if (rate_limiter_.SuspendIfNecessary()) continue;
- }
- if (cpu_profiling_enabled && runtime_profiler_enabled) {
- if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
- return;
- }
- Sleep(HALF_INTERVAL);
+ if (rate_limiter_.SuspendIfNecessary()) continue;
+ if (RuntimeProfiler::IsEnabled()) {
if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
return;
}
- Sleep(HALF_INTERVAL);
- } else {
- if (cpu_profiling_enabled) {
- if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
- this)) {
- return;
- }
- }
- if (runtime_profiler_enabled) {
- if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
- NULL)) {
- return;
- }
- }
- Sleep(FULL_INTERVAL);
}
+ Sleep(FULL_INTERVAL);
}
}
- static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
- if (!sampler->IsProfiling()) return;
- SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
- sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
- }
-
static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
if (!sampler->isolate()->IsInitialized()) return;
sampler->isolate()->runtime_profiler()->NotifyTick();
}
- void SendProfilingSignal(int tid) {
- if (!signal_handler_installed_) return;
- // Glibc doesn't provide a wrapper for tgkill(2).
-#if defined(ANDROID)
- syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
-#else
- syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
-#endif
- }
-
void Sleep(SleepInterval full_or_half) {
// Convert ms to us and subtract 100 us to compensate delays
// occuring during signal delivery.
@@ -1208,15 +1204,12 @@
#endif // ANDROID
}
- const int vm_tgid_;
const int interval_;
RuntimeProfilerRateLimiter rate_limiter_;
// Protects the process wide state below.
static Mutex* mutex_;
static SignalSender* instance_;
- static bool signal_handler_installed_;
- static struct sigaction old_signal_handler_;
private:
DISALLOW_COPY_AND_ASSIGN(SignalSender);
@@ -1225,8 +1218,6 @@
Mutex* SignalSender::mutex_ = NULL;
SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
void OS::SetUp() {
@@ -1254,11 +1245,13 @@
}
#endif
SignalSender::SetUp();
+ CpuProfilerSignalHandler::SetUp();
}
void OS::TearDown() {
SignalSender::TearDown();
+ CpuProfilerSignalHandler::TearDown();
delete limit_mutex;
}
@@ -1279,8 +1272,14 @@
}
+void Sampler::DoSample() {
+ platform_data()->SendProfilingSignal();
+}
+
+
void Sampler::Start() {
ASSERT(!IsActive());
+ CpuProfilerSignalHandler::InstallSignalHandler();
SetActive(true);
SignalSender::AddActiveSampler(this);
}
@@ -1288,6 +1287,7 @@
void Sampler::Stop() {
ASSERT(IsActive());
+ CpuProfilerSignalHandler::RestoreSignalHandler();
SignalSender::RemoveActiveSampler(this);
SetActive(false);
}
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index a216f6e..a570868 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -819,9 +819,8 @@
void SampleContext(Sampler* sampler) {
thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(sampler->isolate());
+ if (sample == NULL) return;
if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
@@ -858,6 +857,7 @@
sampler->SampleStack(sample);
sampler->Tick(sample);
}
+ CpuProfiler::FinishTickSampleEvent(sampler->isolate());
thread_resume(profiled_thread);
}
@@ -910,6 +910,11 @@
}
+void Sampler::DoSample() {
+ // TODO(rogulenko): implement
+}
+
+
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index 408d4dc..f96d9e3 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -731,9 +731,8 @@
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(isolate);
+ if (sample == NULL) return;
// Extracting the sample from the context is extremely machine dependent.
sample->state = isolate->current_vm_state();
@@ -762,6 +761,7 @@
#endif // __NetBSD__
sampler->SampleStack(sample);
sampler->Tick(sample);
+ CpuProfiler::FinishTickSampleEvent(isolate);
}
@@ -964,6 +964,11 @@
}
+void Sampler::DoSample() {
+ // TODO(rogulenko): implement
+}
+
+
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index 4248ea2..36d89e6 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -669,9 +669,8 @@
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(isolate);
+ if (sample == NULL) return;
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
@@ -684,6 +683,7 @@
sampler->SampleStack(sample);
sampler->Tick(sample);
+ CpuProfiler::FinishTickSampleEvent(isolate);
}
class Sampler::PlatformData : public Malloced {
@@ -887,6 +887,11 @@
}
+void Sampler::DoSample() {
+ // TODO(rogulenko): implement
+}
+
+
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 49463be..65d31a9 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -2038,9 +2038,8 @@
CONTEXT context;
memset(&context, 0, sizeof(context));
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(sampler->isolate());
+ if (sample == NULL) return;
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
if (SuspendThread(profiled_thread) == kSuspendFailed) return;
@@ -2060,6 +2059,7 @@
sampler->SampleStack(sample);
sampler->Tick(sample);
}
+ CpuProfiler::FinishTickSampleEvent(sampler->isolate());
ResumeThread(profiled_thread);
}
@@ -2114,6 +2114,11 @@
}
+void Sampler::DoSample() {
+ // TODO(rogulenko): implement
+}
+
+
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
diff --git a/src/platform.h b/src/platform.h
index f50e713..4f8fdc3 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -741,6 +741,9 @@
IncSamplesTaken();
}
+ // Performs platform-specific stack sampling.
+ void DoSample();
+
// This method is called for each sampling period with the current
// program counter.
virtual void Tick(TickSample* sample) = 0;
diff --git a/src/runtime.cc b/src/runtime.cc
index b822814..a514b94 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -5032,15 +5032,6 @@
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
- ASSERT(args.length() == 1);
- Object* obj = args[0];
- return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
- ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
- : obj;
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
diff --git a/src/runtime.h b/src/runtime.h
index da60ee1..c9939d0 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -62,7 +62,6 @@
F(GetIndexedInterceptorElementNames, 1, 1) \
F(GetArgumentsProperty, 1, 1) \
F(ToFastProperties, 1, 1) \
- F(ToSlowProperties, 1, 1) \
F(FinishArrayPrototypeSetup, 1, 1) \
F(SpecialArrayFunctions, 1, 1) \
F(GetDefaultReceiver, 1, 1) \
diff --git a/src/scopes.h b/src/scopes.h
index 6e35d05..b9d151c 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -189,7 +189,7 @@
// Creates a new temporary variable in this scope. The name is only used
// for printing and cannot be used to find the variable. In particular,
// the only way to get hold of the temporary is by keeping the Variable*
- // around.
+ // around. The name should not clash with a legitimate variable names.
Variable* NewTemporary(Handle<String> name);
// Adds the specific declaration node to the list of declarations in
diff --git a/src/spaces.cc b/src/spaces.cc
index ce62877..bc1d7b0 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -447,6 +447,7 @@
chunk->InitializeReservedMemory();
chunk->slots_buffer_ = NULL;
chunk->skip_list_ = NULL;
+ chunk->write_barrier_counter_ = kWriteBarrierCounterGranularity;
chunk->ResetLiveBytes();
Bitmap::Clear(chunk);
chunk->initialize_scan_on_scavenge(false);
diff --git a/src/spaces.h b/src/spaces.h
index 2062f5f..effe06b 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -284,7 +284,9 @@
bool IsClean() {
for (int i = 0; i < CellsCount(); i++) {
- if (cells()[i] != 0) return false;
+ if (cells()[i] != 0) {
+ return false;
+ }
}
return true;
}
@@ -373,6 +375,11 @@
return addr >= area_start() && addr <= area_end();
}
+ // Every n write barrier invocations we go to runtime even though
+ // we could have handled it in generated code. This lets us check
+ // whether we have hit the limit and should do some more marking.
+ static const int kWriteBarrierCounterGranularity = 500;
+
enum MemoryChunkFlags {
IS_EXECUTABLE,
ABOUT_TO_BE_FREED,
@@ -468,6 +475,15 @@
return live_byte_count_;
}
+ int write_barrier_counter() {
+ return static_cast<int>(write_barrier_counter_);
+ }
+
+ void set_write_barrier_counter(int counter) {
+ write_barrier_counter_ = counter;
+ }
+
+
static void IncrementLiveBytesFromGC(Address address, int by) {
MemoryChunk::FromAddress(address)->IncrementLiveBytes(by);
}
@@ -488,9 +504,11 @@
static const size_t kSlotsBufferOffset = kLiveBytesOffset + kIntSize;
- static const size_t kHeaderSize =
+ static const size_t kWriteBarrierCounterOffset =
kSlotsBufferOffset + kPointerSize + kPointerSize;
+ static const size_t kHeaderSize = kWriteBarrierCounterOffset + kPointerSize;
+
static const int kBodyOffset =
CODE_POINTER_ALIGN(MAP_POINTER_ALIGN(kHeaderSize + Bitmap::kSize));
@@ -625,6 +643,7 @@
int live_byte_count_;
SlotsBuffer* slots_buffer_;
SkipList* skip_list_;
+ intptr_t write_barrier_counter_;
static MemoryChunk* Initialize(Heap* heap,
Address base,
diff --git a/src/transitions-inl.h b/src/transitions-inl.h
index 5030616..17c42ed 100644
--- a/src/transitions-inl.h
+++ b/src/transitions-inl.h
@@ -69,12 +69,14 @@
bool TransitionArray::HasElementsTransition() {
- return get(kElementsTransitionIndex) != Smi::FromInt(0);
+ return IsFullTransitionArray() &&
+ get(kElementsTransitionIndex) != Smi::FromInt(0);
}
void TransitionArray::set_elements_transition(Map* transition_map,
WriteBarrierMode mode) {
+ ASSERT(IsFullTransitionArray());
Heap* heap = GetHeap();
WRITE_FIELD(this, kElementsTransitionOffset, transition_map);
CONDITIONAL_WRITE_BARRIER(
@@ -121,12 +123,13 @@
bool TransitionArray::HasPrototypeTransitions() {
- Object* prototype_transitions = get(kPrototypeTransitionsIndex);
- return prototype_transitions != Smi::FromInt(0);
+ return IsFullTransitionArray() &&
+ get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
}
FixedArray* TransitionArray::GetPrototypeTransitions() {
+ ASSERT(IsFullTransitionArray());
Object* prototype_transitions = get(kPrototypeTransitionsIndex);
return FixedArray::cast(prototype_transitions);
}
@@ -140,7 +143,7 @@
void TransitionArray::SetPrototypeTransitions(FixedArray* transitions,
WriteBarrierMode mode) {
- ASSERT(this != NULL);
+ ASSERT(IsFullTransitionArray());
ASSERT(transitions->IsFixedArray());
Heap* heap = GetHeap();
WRITE_FIELD(this, kPrototypeTransitionsOffset, transitions);
@@ -156,6 +159,7 @@
Object** TransitionArray::GetKeySlot(int transition_number) {
+ ASSERT(!IsSimpleTransition());
ASSERT(transition_number < number_of_transitions());
return HeapObject::RawField(
reinterpret_cast<HeapObject*>(this),
@@ -164,24 +168,39 @@
String* TransitionArray::GetKey(int transition_number) {
+ if (IsSimpleTransition()) {
+ Map* target = GetTarget(kSimpleTransitionIndex);
+ int descriptor = target->LastAdded();
+ String* key = target->instance_descriptors()->GetKey(descriptor);
+ return key;
+ }
ASSERT(transition_number < number_of_transitions());
return String::cast(get(ToKeyIndex(transition_number)));
}
void TransitionArray::SetKey(int transition_number, String* key) {
+ ASSERT(!IsSimpleTransition());
ASSERT(transition_number < number_of_transitions());
set(ToKeyIndex(transition_number), key);
}
Map* TransitionArray::GetTarget(int transition_number) {
+ if (IsSimpleTransition()) {
+ ASSERT(transition_number == kSimpleTransitionIndex);
+ return Map::cast(get(kSimpleTransitionTarget));
+ }
ASSERT(transition_number < number_of_transitions());
return Map::cast(get(ToTargetIndex(transition_number)));
}
void TransitionArray::SetTarget(int transition_number, Map* value) {
+ if (IsSimpleTransition()) {
+ ASSERT(transition_number == kSimpleTransitionIndex);
+ return set(kSimpleTransitionTarget, value);
+ }
ASSERT(transition_number < number_of_transitions());
set(ToTargetIndex(transition_number), value);
}
diff --git a/src/transitions.cc b/src/transitions.cc
index 199fcc2..7233f73 100644
--- a/src/transitions.cc
+++ b/src/transitions.cc
@@ -35,8 +35,8 @@
namespace internal {
-MaybeObject* TransitionArray::Allocate(int number_of_transitions,
- JSGlobalPropertyCell* descriptors_cell) {
+static MaybeObject* AllocateRaw(int length,
+ JSGlobalPropertyCell* descriptors_cell) {
Heap* heap = Isolate::Current()->heap();
if (descriptors_cell == NULL) {
@@ -45,13 +45,22 @@
if (!maybe_cell->To(&descriptors_cell)) return maybe_cell;
}
- // Use FixedArray to not use DescriptorArray::cast on incomplete object.
+ // Use FixedArray to not use TransitionArray::cast on incomplete object.
FixedArray* array;
- MaybeObject* maybe_array =
- heap->AllocateFixedArray(ToKeyIndex(number_of_transitions));
+ MaybeObject* maybe_array = heap->AllocateFixedArray(length);
if (!maybe_array->To(&array)) return maybe_array;
- array->set(kDescriptorsPointerIndex, descriptors_cell);
+ array->set(TransitionArray::kDescriptorsPointerIndex, descriptors_cell);
+ return array;
+}
+
+
+MaybeObject* TransitionArray::Allocate(int number_of_transitions,
+ JSGlobalPropertyCell* descriptors_cell) {
+ FixedArray* array;
+ MaybeObject* maybe_array =
+ AllocateRaw(ToKeyIndex(number_of_transitions), descriptors_cell);
+ if (!maybe_array->To(&array)) return maybe_array;
array->set(kElementsTransitionIndex, Smi::FromInt(0));
array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
return array;
@@ -72,22 +81,50 @@
}
-MaybeObject* TransitionArray::NewWith(
- String* name,
- Map* target,
- JSGlobalPropertyCell* descriptors_pointer,
- Object* back_pointer) {
+MaybeObject* TransitionArray::NewWith(SimpleTransitionFlag flag,
+ String* key,
+ Map* target,
+ JSGlobalPropertyCell* descriptors_pointer,
+ Object* back_pointer) {
TransitionArray* result;
+ MaybeObject* maybe_result;
- MaybeObject* maybe_array = TransitionArray::Allocate(1, descriptors_pointer);
- if (!maybe_array->To(&result)) return maybe_array;
-
- result->NoIncrementalWriteBarrierSet(0, name, target);
+ if (flag == SIMPLE_TRANSITION) {
+ maybe_result = AllocateRaw(kSimpleTransitionSize, descriptors_pointer);
+ if (!maybe_result->To(&result)) return maybe_result;
+ result->set(kSimpleTransitionTarget, target);
+ } else {
+ maybe_result = Allocate(1, descriptors_pointer);
+ if (!maybe_result->To(&result)) return maybe_result;
+ result->NoIncrementalWriteBarrierSet(0, key, target);
+ }
result->set_back_pointer_storage(back_pointer);
return result;
}
+MaybeObject* TransitionArray::AllocateDescriptorsHolder(
+ JSGlobalPropertyCell* descriptors_pointer) {
+ return AllocateRaw(kDescriptorsHolderSize, descriptors_pointer);
+}
+
+
+MaybeObject* TransitionArray::ExtendToFullTransitionArray() {
+ ASSERT(!IsFullTransitionArray());
+ int nof = number_of_transitions();
+ TransitionArray* result;
+ MaybeObject* maybe_result = Allocate(nof, descriptors_pointer());
+ if (!maybe_result->To(&result)) return maybe_result;
+
+ if (nof == 1) {
+ result->NoIncrementalWriteBarrierCopyFrom(this, kSimpleTransitionIndex, 0);
+ }
+
+ result->set_back_pointer_storage(back_pointer_storage());
+ return result;
+}
+
+
MaybeObject* TransitionArray::CopyInsert(String* name, Map* target) {
TransitionArray* result;
diff --git a/src/transitions.h b/src/transitions.h
index b87b973..52a043c 100644
--- a/src/transitions.h
+++ b/src/transitions.h
@@ -91,7 +91,7 @@
// Returns the number of transitions in the array.
int number_of_transitions() {
- ASSERT(length() >= kFirstIndex);
+ if (IsSimpleTransition()) return 1;
int len = length();
return len <= kFirstIndex ? 0 : (len - kFirstIndex) / kTransitionSize;
}
@@ -100,11 +100,17 @@
// Allocate a new transition array with a single entry.
static MUST_USE_RESULT MaybeObject* NewWith(
- String* name,
+ SimpleTransitionFlag flag,
+ String* key,
Map* target,
JSGlobalPropertyCell* descriptor_pointer,
Object* back_pointer);
+ static MUST_USE_RESULT MaybeObject* AllocateDescriptorsHolder(
+ JSGlobalPropertyCell* descriptor_pointer);
+
+ MUST_USE_RESULT MaybeObject* ExtendToFullTransitionArray();
+
// Copy the transition array, inserting a new transition.
// TODO(verwaest): This should not cause an existing transition to be
// overwritten.
@@ -123,6 +129,10 @@
int number_of_transitions,
JSGlobalPropertyCell* descriptors_cell);
+ bool IsDescriptorsHolder() { return length() == kDescriptorsHolderSize; }
+ bool IsSimpleTransition() { return length() == kSimpleTransitionSize; }
+ bool IsFullTransitionArray() { return length() >= kFirstIndex; }
+
// Casting.
static inline TransitionArray* cast(Object* obj);
@@ -131,20 +141,30 @@
static const int kDescriptorsPointerIndex = 0;
static const int kBackPointerStorageIndex = 1;
+ static const int kDescriptorsHolderSize = 2;
+
+ // Layout for full transition arrays.
static const int kElementsTransitionIndex = 2;
static const int kPrototypeTransitionsIndex = 3;
static const int kFirstIndex = 4;
- // Layout transition array header.
+ // Layout for simple transition arrays.
+ static const int kSimpleTransitionTarget = 2;
+ static const int kSimpleTransitionSize = 3;
+ static const int kSimpleTransitionIndex = 0;
+ STATIC_ASSERT(kSimpleTransitionIndex != kNotFound);
+
static const int kDescriptorsPointerOffset = FixedArray::kHeaderSize;
static const int kBackPointerStorageOffset = kDescriptorsPointerOffset +
kPointerSize;
+
+ // Layout for the full transition array header.
static const int kElementsTransitionOffset = kBackPointerStorageOffset +
kPointerSize;
static const int kPrototypeTransitionsOffset = kElementsTransitionOffset +
kPointerSize;
- // Layout of map transition.
+ // Layout of map transition entries in full transition arrays.
static const int kTransitionKey = 0;
static const int kTransitionTarget = 1;
static const int kTransitionSize = 2;
diff --git a/src/utils.h b/src/utils.h
index dc3a171..e659de2 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -974,7 +974,7 @@
T Mask(E element) const {
// The strange typing in ASSERT is necessary to avoid stupid warnings, see:
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43680
- ASSERT(element < static_cast<int>(sizeof(T) * CHAR_BIT));
+ ASSERT(static_cast<int>(element) < static_cast<int>(sizeof(T) * CHAR_BIT));
return 1 << element;
}
diff --git a/src/v8globals.h b/src/v8globals.h
index 3d214f8..1d22a11 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -438,6 +438,7 @@
VFP3 = 1, // ARM
ARMv7 = 2, // ARM
VFP2 = 3, // ARM
+ SUDIV = 4, // ARM
SAHF = 0, // x86
FPU = 1}; // MIPS
diff --git a/src/version.cc b/src/version.cc
index 9ec9024..5969267 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 14
-#define BUILD_NUMBER 1
-#define PATCH_LEVEL 4
+#define BUILD_NUMBER 2
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 62a89b8..0bad960 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -2262,21 +2262,28 @@
__ movsd(double_scratch2, double_result); // Load double_exponent with 1.
// Get absolute value of exponent.
- Label no_neg, while_true, no_multiply;
+ Label no_neg, while_true, while_false;
__ testl(scratch, scratch);
__ j(positive, &no_neg, Label::kNear);
__ negl(scratch);
__ bind(&no_neg);
+ __ j(zero, &while_false, Label::kNear);
+ __ shrl(scratch, Immediate(1));
+ // Above condition means CF==0 && ZF==0. This means that the
+ // bit that has been shifted out is 0 and the result is not 0.
+ __ j(above, &while_true, Label::kNear);
+ __ movsd(double_result, double_scratch);
+ __ j(zero, &while_false, Label::kNear);
+
__ bind(&while_true);
__ shrl(scratch, Immediate(1));
- __ j(not_carry, &no_multiply, Label::kNear);
- __ mulsd(double_result, double_scratch);
- __ bind(&no_multiply);
-
__ mulsd(double_scratch, double_scratch);
+ __ j(above, &while_true, Label::kNear);
+ __ mulsd(double_result, double_scratch);
__ j(not_zero, &while_true);
+ __ bind(&while_false);
// If the exponent is negative, return 1/result.
__ testl(exponent, exponent);
__ j(greater, &done);
@@ -6137,6 +6144,11 @@
}
+bool CodeStub::CanUseFPRegisters() {
+ return true; // Always have SSE2 on x64.
+}
+
+
// Takes the input in 3 registers: address_ value_ and object_. A pointer to
// the value has just been written into the object, now this stub makes sure
// we keep the GC informed. The word in the object where the value has been
@@ -6269,6 +6281,17 @@
Label need_incremental;
Label need_incremental_pop_object;
+ __ movq(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask));
+ __ and_(regs_.scratch0(), regs_.object());
+ __ movq(regs_.scratch1(),
+ Operand(regs_.scratch0(),
+ MemoryChunk::kWriteBarrierCounterOffset));
+ __ subq(regs_.scratch1(), Immediate(1));
+ __ movq(Operand(regs_.scratch0(),
+ MemoryChunk::kWriteBarrierCounterOffset),
+ regs_.scratch1());
+ __ j(negative, &need_incremental);
+
// Let's look at the color of the object: If it is not black we don't have
// to inform the incremental marker.
__ JumpIfBlack(regs_.object(),
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 954d043..1949c31 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -2118,37 +2118,15 @@
ASSERT(prop != NULL);
ASSERT(prop->key()->AsLiteral() != NULL);
- // If the assignment starts a block of assignments to the same object,
- // change to slow case to avoid the quadratic behavior of repeatedly
- // adding fast properties.
- if (expr->starts_initialization_block()) {
- __ push(result_register());
- __ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
- __ CallRuntime(Runtime::kToSlowProperties, 1);
- __ pop(result_register());
- }
-
// Record source code position before IC call.
SetSourcePosition(expr->position());
__ Move(rcx, prop->key()->AsLiteral()->handle());
- if (expr->ends_initialization_block()) {
- __ movq(rdx, Operand(rsp, 0));
- } else {
- __ pop(rdx);
- }
+ __ pop(rdx);
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
- // If the assignment ends an initialization block, revert to fast case.
- if (expr->ends_initialization_block()) {
- __ push(rax); // Result of assignment, saved even if not needed.
- __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
- __ CallRuntime(Runtime::kToFastProperties, 1);
- __ pop(rax);
- __ Drop(1);
- }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(rax);
}
@@ -2157,23 +2135,8 @@
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
// Assignment to a property, using a keyed store IC.
- // If the assignment starts a block of assignments to the same object,
- // change to slow case to avoid the quadratic behavior of repeatedly
- // adding fast properties.
- if (expr->starts_initialization_block()) {
- __ push(result_register());
- // Receiver is now under the key and value.
- __ push(Operand(rsp, 2 * kPointerSize));
- __ CallRuntime(Runtime::kToSlowProperties, 1);
- __ pop(result_register());
- }
-
__ pop(rcx);
- if (expr->ends_initialization_block()) {
- __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
- } else {
- __ pop(rdx);
- }
+ __ pop(rdx);
// Record source code position before IC call.
SetSourcePosition(expr->position());
Handle<Code> ic = is_classic_mode()
@@ -2181,15 +2144,6 @@
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
- // If the assignment ends an initialization block, revert to fast case.
- if (expr->ends_initialization_block()) {
- __ pop(rdx);
- __ push(rax); // Result of assignment, saved even if not needed.
- __ push(rdx);
- __ CallRuntime(Runtime::kToFastProperties, 1);
- __ pop(rax);
- }
-
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(rax);
}
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 0fd8a40..efa07a8 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -623,6 +623,123 @@
}
+static void KeyedStoreGenerateGenericHelper(
+ MacroAssembler* masm,
+ Label* fast_object,
+ Label* fast_double,
+ Label* slow,
+ KeyedStoreCheckMap check_map,
+ KeyedStoreIncrementLength increment_length) {
+ Label transition_smi_elements;
+ Label finish_object_store, non_double_value, transition_double_elements;
+ Label fast_double_without_map_check;
+ // Fast case: Do the store, could be either Object or double.
+ __ bind(fast_object);
+ // rax: value
+ // rbx: receiver's elements array (a FixedArray)
+ // rcx: index
+ // rdx: receiver (a JSArray)
+ // r9: map of receiver
+ if (check_map == kCheckMap) {
+ __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
+ __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
+ __ j(not_equal, fast_double);
+ }
+ // Smi stores don't require further checks.
+ Label non_smi_value;
+ __ JumpIfNotSmi(rax, &non_smi_value);
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ leal(rdi, Operand(rcx, 1));
+ __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
+ }
+ // It's irrelevant whether array is smi-only or not when writing a smi.
+ __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
+ rax);
+ __ ret(0);
+
+ __ bind(&non_smi_value);
+ // Writing a non-smi, check whether array allows non-smi elements.
+ // r9: receiver's map
+ __ CheckFastObjectElements(r9, &transition_smi_elements);
+
+ __ bind(&finish_object_store);
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ leal(rdi, Operand(rcx, 1));
+ __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
+ }
+ __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
+ rax);
+ __ movq(rdx, rax); // Preserve the value which is returned.
+ __ RecordWriteArray(
+ rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+ __ ret(0);
+
+ __ bind(fast_double);
+ if (check_map == kCheckMap) {
+ // Check for fast double array case. If this fails, call through to the
+ // runtime.
+ // rdi: elements array's map
+ __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
+ __ j(not_equal, slow);
+ }
+ __ bind(&fast_double_without_map_check);
+ __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
+ &transition_double_elements);
+ if (increment_length == kIncrementLength) {
+ // Add 1 to receiver->length.
+ __ leal(rdi, Operand(rcx, 1));
+ __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
+ }
+ __ ret(0);
+
+ __ bind(&transition_smi_elements);
+ __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
+
+ // Transition the array appropriately depending on the value type.
+ __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset));
+ __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
+ __ j(not_equal, &non_double_value);
+
+ // Value is a double. Transition FAST_SMI_ELEMENTS ->
+ // FAST_DOUBLE_ELEMENTS and complete the store.
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
+ rbx,
+ rdi,
+ slow);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow);
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ jmp(&fast_double_without_map_check);
+
+ __ bind(&non_double_value);
+ // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_ELEMENTS,
+ rbx,
+ rdi,
+ slow);
+ ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+
+ __ bind(&transition_double_elements);
+ // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+ // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+ __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+ FAST_ELEMENTS,
+ rbx,
+ rdi,
+ slow);
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow);
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ jmp(&finish_object_store);
+}
+
+
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
@@ -631,11 +748,9 @@
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- Label slow, slow_with_tagged_index, fast, array, extra, check_extra_double;
- Label fast_object_with_map_check, fast_object_without_map_check;
- Label fast_double_with_map_check, fast_double_without_map_check;
- Label transition_smi_elements, finish_object_store, non_double_value;
- Label transition_double_elements;
+ Label slow, slow_with_tagged_index, fast_object, fast_object_grow;
+ Label fast_double, fast_double_grow;
+ Label array, extra, check_if_double_array;
// Check that the object isn't a smi.
__ JumpIfSmi(rdx, &slow_with_tagged_index);
@@ -666,7 +781,7 @@
// rax: value
// rbx: FixedArray
// rcx: index
- __ j(above, &fast_object_with_map_check);
+ __ j(above, &fast_object);
// Slow case: call runtime.
__ bind(&slow);
@@ -690,18 +805,14 @@
// Increment index to get new length.
__ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
__ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
- __ j(not_equal, &check_extra_double);
- __ leal(rdi, Operand(rcx, 1));
- __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
- __ jmp(&fast_object_without_map_check);
+ __ j(not_equal, &check_if_double_array);
+ __ jmp(&fast_object_grow);
- __ bind(&check_extra_double);
+ __ bind(&check_if_double_array);
// rdi: elements array's map
__ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
__ j(not_equal, &slow);
- __ leal(rdi, Operand(rcx, 1));
- __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
- __ jmp(&fast_double_without_map_check);
+ __ jmp(&fast_double_grow);
// Array case: Get the length and the elements array from the JS
// array. Check that the array is in fast mode (and writable); if it
@@ -717,92 +828,10 @@
__ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
__ j(below_equal, &extra);
- // Fast case: Do the store.
- __ bind(&fast_object_with_map_check);
- // rax: value
- // rbx: receiver's elements array (a FixedArray)
- // rcx: index
- // rdx: receiver (a JSArray)
- __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
- __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
- __ j(not_equal, &fast_double_with_map_check);
- __ bind(&fast_object_without_map_check);
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(rax, &non_smi_value);
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
- rax);
- __ ret(0);
-
- __ bind(&non_smi_value);
- // Writing a non-smi, check whether array allows non-smi elements.
- // r9: receiver's map
- __ CheckFastObjectElements(r9, &transition_smi_elements);
- __ bind(&finish_object_store);
- __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
- rax);
- __ movq(rdx, rax); // Preserve the value which is returned.
- __ RecordWriteArray(
- rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ ret(0);
-
- __ bind(&fast_double_with_map_check);
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- // rdi: elements array's map
- __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
- __ j(not_equal, &slow);
- __ bind(&fast_double_without_map_check);
- // If the value is a number, store it as a double in the FastDoubleElements
- // array.
- __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
- &transition_double_elements);
- __ ret(0);
-
- __ bind(&transition_smi_elements);
- __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
-
- // Transition the array appropriately depending on the value type.
- __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset));
- __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
- __ j(not_equal, &non_double_value);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS,
- rbx,
- rdi,
- &slow);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
- __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_ELEMENTS,
- rbx,
- rdi,
- &slow);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
- __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
- FAST_ELEMENTS,
- rbx,
- rdi,
- &slow);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
- __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
+ KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
+ &slow, kCheckMap, kDontIncrementLength);
+ KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
+ &slow, kDontCheckMap, kIncrementLength);
}
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 8e887cd..8547b09 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1125,8 +1125,11 @@
__ testl(left, left);
__ j(not_zero, &done, Label::kNear);
if (right->IsConstantOperand()) {
- if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
+ if (ToInteger32(LConstantOperand::cast(right)) < 0) {
DeoptimizeIf(no_condition, instr->environment());
+ } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
+ __ cmpl(kScratchRegister, Immediate(0));
+ DeoptimizeIf(less, instr->environment());
}
} else if (right->IsStackSlot()) {
__ orl(kScratchRegister, ToOperand(right));
@@ -3774,11 +3777,17 @@
__ cmpq(reg, reg2);
}
} else {
+ Operand length = ToOperand(instr->length());
if (instr->index()->IsConstantOperand()) {
- __ cmpq(ToOperand(instr->length()),
- Immediate(ToInteger32(LConstantOperand::cast(instr->index()))));
+ int constant_index =
+ ToInteger32(LConstantOperand::cast(instr->index()));
+ if (instr->hydrogen()->length()->representation().IsTagged()) {
+ __ Cmp(length, Smi::FromInt(constant_index));
+ } else {
+ __ cmpq(length, Immediate(constant_index));
+ }
} else {
- __ cmpq(ToOperand(instr->length()), ToRegister(instr->index()));
+ __ cmpq(length, ToRegister(instr->index()));
}
}
DeoptimizeIf(below_equal, instr->environment());
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 177e734..dd3054f 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -2128,6 +2128,7 @@
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
+ ASSERT(argument_count_ == 0);
allocator_->MarkAsOsrEntry();
current_block_->last_environment()->set_ast_id(instr->ast_id());
return AssignEnvironment(new(zone()) LOsrEntry);
@@ -2267,7 +2268,7 @@
HEnvironment* env = current_block_->last_environment();
- if (instr->arguments_pushed()) {
+ if (env->entry()->arguments_pushed()) {
int argument_count = env->arguments_environment()->parameter_count();
pop = new(zone()) LDrop(argument_count);
argument_count_ -= argument_count;