Version 3.23.1
Made HCapturedObjects non-deletable for DCE. (issue 2987)
Use a fixed random seed per default. (issue 1880, 2885)
Fixed y-umlaut to uppercase. (issue 2984)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@17579 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index d106abb..21746d3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2013-11-08: Version 3.23.1
+
+ Made HCapturedObjects non-deletable for DCE. (issue 2987)
+
+ Use a fixed random seed per default. (issue 1880, 2885)
+
+ Fixed y-umlaut to uppercase. (issue 2984)
+
+ Performance and stability improvements on all platforms.
+
+
2013-11-06: Version 3.23.0
Fixed loading message from an Error object. (Chromium issue 306220)
diff --git a/Makefile b/Makefile
index bbec440..64bf7bc 100644
--- a/Makefile
+++ b/Makefile
@@ -104,6 +104,10 @@
ifeq ($(unalignedaccess), on)
GYPFLAGS += -Dv8_can_use_unaligned_accesses=true
endif
+# randomseed=12345, disable random seed via randomseed=0
+ifdef randomseed
+ GYPFLAGS += -Dv8_random_seed=$(randomseed)
+endif
# soname_version=1.2.3
ifdef soname_version
GYPFLAGS += -Dsoname_version=$(soname_version)
diff --git a/build/features.gypi b/build/features.gypi
index 7863b1c..08ea11a 100644
--- a/build/features.gypi
+++ b/build/features.gypi
@@ -109,7 +109,7 @@
'Release': {
'variables': {
'v8_enable_extra_checks%': 0,
- 'v8_enable_handle_zapping%': 0,
+ 'v8_enable_handle_zapping%': 1,
},
'conditions': [
['v8_enable_extra_checks==1', {
diff --git a/include/v8.h b/include/v8.h
index 5286baa..1f8cbfd 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -5414,7 +5414,7 @@
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptyStringRootIndex = 132;
+ static const int kEmptyStringRootIndex = 134;
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
diff --git a/src/accessors.cc b/src/accessors.cc
index eb8be5f..4da9dd4 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -617,7 +617,7 @@
if (is_observed && !old_value->SameValue(*value)) {
JSObject::EnqueueChangeRecord(
- function, "updated", isolate->factory()->prototype_string(), old_value);
+ function, "update", isolate->factory()->prototype_string(), old_value);
}
return *function;
diff --git a/src/api.cc b/src/api.cc
index b90e693..401007b 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -3136,7 +3136,7 @@
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> obj = i::SetProperty(
+ i::Handle<i::Object> obj = i::Runtime::SetObjectProperty(
isolate,
self,
key_obj,
diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h
index dff8162..f93a9a6 100644
--- a/src/arm/assembler-arm-inl.h
+++ b/src/arm/assembler-arm-inl.h
@@ -126,21 +126,21 @@
Object* RelocInfo::target_object() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
- return reinterpret_cast<Object*>(Assembler::target_pointer_at(pc_));
+ return reinterpret_cast<Object*>(Assembler::target_address_at(pc_));
}
Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
return Handle<Object>(reinterpret_cast<Object**>(
- Assembler::target_pointer_at(pc_)));
+ Assembler::target_address_at(pc_)));
}
void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
ASSERT(!target->IsConsString());
- Assembler::set_target_pointer_at(pc_, reinterpret_cast<Address>(target));
+ Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
if (mode == UPDATE_WRITE_BARRIER &&
host() != NULL &&
target->IsHeapObject()) {
@@ -263,7 +263,7 @@
IsCodeTarget(rmode_) ||
IsRuntimeEntry(rmode_) ||
IsExternalReference(rmode_));
- Assembler::set_target_pointer_at(pc_, NULL);
+ Assembler::set_target_address_at(pc_, NULL);
}
@@ -397,7 +397,7 @@
}
-Address Assembler::target_pointer_at(Address pc) {
+Address Assembler::target_address_at(Address pc) {
if (IsMovW(Memory::int32_at(pc))) {
ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
Instruction* instr = Instruction::At(pc);
@@ -464,7 +464,7 @@
}
-void Assembler::set_target_pointer_at(Address pc, Address target) {
+void Assembler::set_target_address_at(Address pc, Address target) {
if (IsMovW(Memory::int32_at(pc))) {
ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
@@ -495,16 +495,6 @@
}
-Address Assembler::target_address_at(Address pc) {
- return target_pointer_at(pc);
-}
-
-
-void Assembler::set_target_address_at(Address pc, Address target) {
- set_target_pointer_at(pc, target);
-}
-
-
} } // namespace v8::internal
#endif // V8_ARM_ASSEMBLER_ARM_INL_H_
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 0437b3f..9bfdc9e 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -785,10 +785,6 @@
// the branch/call instruction at pc, or the object in a mov.
INLINE(static Address target_pointer_address_at(Address pc));
- // Read/Modify the pointer in the branch/call/move instruction at pc.
- INLINE(static Address target_pointer_at(Address pc));
- INLINE(static void set_target_pointer_at(Address pc, Address target));
-
// Read/Modify the code target address in the branch/call instruction at pc.
INLINE(static Address target_address_at(Address pc));
INLINE(static void set_target_address_at(Address pc, Address target));
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 1ee612b..8fb1e15 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -1634,6 +1634,9 @@
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
+
+ int depth = 1;
+ expr->BuildConstantProperties(isolate(), &depth);
Handle<FixedArray> constant_properties = expr->constant_properties();
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
@@ -1648,7 +1651,7 @@
__ mov(r0, Operand(Smi::FromInt(flags)));
int properties_count = constant_properties->length() / 2;
if ((FLAG_track_double_fields && expr->may_store_doubles()) ||
- expr->depth() > 1 || Serializer::enabled() ||
+ depth > 1 || Serializer::enabled() ||
flags != ObjectLiteral::kFastElements ||
properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
__ Push(r3, r2, r1, r0);
@@ -1767,6 +1770,8 @@
void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral");
+ int depth = 1;
+ expr->BuildConstantElements(isolate(), &depth);
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements();
@@ -1790,8 +1795,7 @@
__ CallStub(&stub);
__ IncrementCounter(
isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2);
- } else if (expr->depth() > 1 ||
- Serializer::enabled() ||
+ } else if (depth > 1 || Serializer::enabled() ||
length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ Push(r3, r2, r1);
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
@@ -4394,14 +4398,44 @@
PrepareForBailoutForId(prop->LoadId(), TOS_REG);
}
- // Call ToNumber only if operand is not a smi.
- Label no_conversion;
+ // Inline smi case if we are in a loop.
+ Label stub_call, done;
+ JumpPatchSite patch_site(masm_);
+
+ int count_value = expr->op() == Token::INC ? 1 : -1;
if (ShouldInlineSmiCase(expr->op())) {
- __ JumpIfSmi(r0, &no_conversion);
+ Label slow;
+ patch_site.EmitJumpIfNotSmi(r0, &slow);
+
+ // Save result for postfix expressions.
+ if (expr->is_postfix()) {
+ if (!context()->IsEffect()) {
+ // Save the result on the stack. If we have a named or keyed property
+ // we store the result under the receiver that is currently on top
+ // of the stack.
+ switch (assign_type) {
+ case VARIABLE:
+ __ push(r0);
+ break;
+ case NAMED_PROPERTY:
+ __ str(r0, MemOperand(sp, kPointerSize));
+ break;
+ case KEYED_PROPERTY:
+ __ str(r0, MemOperand(sp, 2 * kPointerSize));
+ break;
+ }
+ }
+ }
+
+ __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
+ __ b(vc, &done);
+ // Call stub. Undo operation first.
+ __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
+ __ jmp(&stub_call);
+ __ bind(&slow);
}
ToNumberStub convert_stub;
__ CallStub(&convert_stub);
- __ bind(&no_conversion);
// Save result for postfix expressions.
if (expr->is_postfix()) {
@@ -4424,22 +4458,7 @@
}
- // Inline smi case if we are in a loop.
- Label stub_call, done;
- JumpPatchSite patch_site(masm_);
-
- int count_value = expr->op() == Token::INC ? 1 : -1;
- if (ShouldInlineSmiCase(expr->op())) {
- __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
- __ b(vs, &stub_call);
- // We could eliminate this smi check if we split the code at
- // the first smi check before calling ToNumber.
- patch_site.EmitJumpIfSmi(r0, &done);
-
- __ bind(&stub_call);
- // Call stub. Undo operation first.
- __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
- }
+ __ bind(&stub_call);
__ mov(r1, r0);
__ mov(r0, Operand(Smi::FromInt(count_value)));
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 4019461..025a590 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1268,6 +1268,21 @@
Operand(masm->isolate()->factory()->fixed_array_map()));
__ b(ne, fast_double);
}
+
+ // HOLECHECK: guards "A[i] = V"
+ // We have to go to the runtime if the current value is the hole because
+ // there may be a callback on the element
+ Label holecheck_passed1;
+ __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ ldr(scratch_value,
+ MemOperand::PointerAddressFromSmiKey(address, key, PreIndex));
+ __ cmp(scratch_value, Operand(masm->isolate()->factory()->the_hole_value()));
+ __ b(ne, &holecheck_passed1);
+ __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
+ slow);
+
+ __ bind(&holecheck_passed1);
+
// Smi stores don't require further checks.
Label non_smi_value;
__ JumpIfNotSmi(value, &non_smi_value);
@@ -1315,6 +1330,20 @@
__ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex);
__ b(ne, slow);
}
+
+ // HOLECHECK: guards "A[i] double hole?"
+ // We have to see if the double version of the hole is present. If so
+ // go to the runtime.
+ __ add(address, elements,
+ Operand((FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32))
+ - kHeapObjectTag));
+ __ ldr(scratch_value,
+ MemOperand(address, key, LSL, kPointerSizeLog2, PreIndex));
+ __ cmp(scratch_value, Operand(kHoleNanUpper32));
+ __ b(ne, &fast_double_without_map_check);
+ __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
+ slow);
+
__ bind(&fast_double_without_map_check);
__ StoreNumberToDoubleElements(value, key, elements, r3, d0,
&transition_double_elements);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 86d5d2b..14db24f 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1884,11 +1884,18 @@
}
+LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
+}
+
+
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegisterOrConstant(instr->index());
LOperand* value = UseRegister(instr->value());
- return new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
+ return new(zone()) LSeqStringSetChar(string, index, value);
}
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index ed07229..7574e15 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -156,6 +156,7 @@
V(Random) \
V(RegExpLiteral) \
V(Return) \
+ V(SeqStringGetChar) \
V(SeqStringSetChar) \
V(ShiftI) \
V(SmiTag) \
@@ -1360,27 +1361,37 @@
};
+class LSeqStringGetChar V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+ LSeqStringGetChar(LOperand* string, LOperand* index) {
+ inputs_[0] = string;
+ inputs_[1] = index;
+ }
+
+ LOperand* string() const { return inputs_[0]; }
+ LOperand* index() const { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar, "seq-string-get-char")
+ DECLARE_HYDROGEN_ACCESSOR(SeqStringGetChar)
+};
+
+
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LSeqStringSetChar(String::Encoding encoding,
- LOperand* string,
+ LSeqStringSetChar(LOperand* string,
LOperand* index,
- LOperand* value) : encoding_(encoding) {
+ LOperand* value) {
inputs_[0] = string;
inputs_[1] = index;
inputs_[2] = value;
}
- String::Encoding encoding() { return encoding_; }
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
-
- private:
- String::Encoding encoding_;
};
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index fbe8e17..bf8b7b9 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -769,13 +769,39 @@
return;
}
- ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on ARM.
- if (FLAG_deopt_every_n_times == 1 &&
- !info()->IsStub() &&
- info()->opt_count() == id) {
- ASSERT(frame_is_built_);
- __ Call(entry, RelocInfo::RUNTIME_ENTRY);
- return;
+ if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
+ Register scratch = scratch0();
+ ExternalReference count = ExternalReference::stress_deopt_count(isolate());
+
+ // Store the condition on the stack if necessary
+ if (condition != al) {
+ __ mov(scratch, Operand::Zero(), LeaveCC, NegateCondition(condition));
+ __ mov(scratch, Operand(1), LeaveCC, condition);
+ __ push(scratch);
+ }
+
+ __ push(r1);
+ __ mov(scratch, Operand(count));
+ __ ldr(r1, MemOperand(scratch));
+ __ sub(r1, r1, Operand(1), SetCC);
+ __ movw(r1, FLAG_deopt_every_n_times, eq);
+ __ str(r1, MemOperand(scratch));
+ __ pop(r1);
+
+ if (condition != al) {
+ // Clean up the stack before the deoptimizer call
+ __ pop(scratch);
+ }
+
+ __ Call(entry, RelocInfo::RUNTIME_ENTRY, eq);
+
+ // 'Restore' the condition in a slightly hacky way. (It would be better
+ // to use 'msr' and 'mrs' instructions here, but they are not supported by
+ // our ARM simulator).
+ if (condition != al) {
+ condition = ne;
+ __ cmp(scratch, Operand::Zero());
+ }
}
if (info()->ShouldTrapOnDeopt()) {
@@ -1924,14 +1950,37 @@
}
-void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
- Register string = ToRegister(instr->string());
- LOperand* index_op = instr->index();
- Register value = ToRegister(instr->value());
+MemOperand LCodeGen::BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding) {
+ if (index->IsConstantOperand()) {
+ int offset = ToInteger32(LConstantOperand::cast(index));
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ offset *= kUC16Size;
+ }
+ STATIC_ASSERT(kCharSize == 1);
+ return FieldMemOperand(string, SeqString::kHeaderSize + offset);
+ }
Register scratch = scratch0();
- String::Encoding encoding = instr->encoding();
+ ASSERT(!scratch.is(string));
+ ASSERT(!scratch.is(ToRegister(index)));
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ add(scratch, string, Operand(ToRegister(index)));
+ } else {
+ STATIC_ASSERT(kUC16Size == 2);
+ __ add(scratch, string, Operand(ToRegister(index), LSL, 1));
+ }
+ return FieldMemOperand(scratch, SeqString::kHeaderSize);
+}
+
+
+void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
+ Register string = ToRegister(instr->string());
+ Register result = ToRegister(instr->result());
if (FLAG_debug_code) {
+ Register scratch = scratch0();
__ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
__ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
@@ -1944,24 +1993,39 @@
__ Check(eq, kUnexpectedStringType);
}
- if (index_op->IsConstantOperand()) {
- int constant_index = ToInteger32(LConstantOperand::cast(index_op));
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ strb(value,
- FieldMemOperand(string, SeqString::kHeaderSize + constant_index));
- } else {
- __ strh(value,
- FieldMemOperand(string, SeqString::kHeaderSize + constant_index * 2));
- }
+ MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ ldrb(result, operand);
} else {
- Register index = ToRegister(index_op);
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ add(scratch, string, Operand(index));
- __ strb(value, FieldMemOperand(scratch, SeqString::kHeaderSize));
- } else {
- __ add(scratch, string, Operand(index, LSL, 1));
- __ strh(value, FieldMemOperand(scratch, SeqString::kHeaderSize));
- }
+ __ ldrh(result, operand);
+ }
+}
+
+
+void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
+ Register string = ToRegister(instr->string());
+ Register value = ToRegister(instr->value());
+
+ if (FLAG_debug_code) {
+ Register scratch = scratch0();
+ __ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
+ __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+
+ __ and_(scratch, scratch,
+ Operand(kStringRepresentationMask | kStringEncodingMask));
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ __ cmp(scratch, Operand(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
+ __ Check(eq, kUnexpectedStringType);
+ }
+
+ MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ strb(value, operand);
+ } else {
+ __ strh(value, operand);
}
}
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index a9b85c8..cbd6b9c 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -273,6 +273,10 @@
Register ToRegister(int index) const;
DwVfpRegister ToDoubleRegister(int index) const;
+ MemOperand BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding);
+
void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 9c21b81..7a5bef8 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -3929,6 +3929,32 @@
}
+void MacroAssembler::JumpIfDictionaryInPrototypeChain(
+ Register object,
+ Register scratch0,
+ Register scratch1,
+ Label* found) {
+ ASSERT(!scratch1.is(scratch0));
+ Factory* factory = isolate()->factory();
+ Register current = scratch0;
+ Label loop_again;
+
+ // scratch contained elements pointer.
+ mov(current, object);
+
+ // Loop based on the map going up the prototype chain.
+ bind(&loop_again);
+ ldr(current, FieldMemOperand(current, HeapObject::kMapOffset));
+ ldr(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
+ Ubfx(scratch1, scratch1, Map::kElementsKindShift, Map::kElementsKindBitCount);
+ cmp(scratch1, Operand(DICTIONARY_ELEMENTS));
+ b(eq, found);
+ ldr(current, FieldMemOperand(current, Map::kPrototypeOffset));
+ cmp(current, Operand(factory->null_value()));
+ b(ne, &loop_again);
+}
+
+
#ifdef DEBUG
bool AreAliased(Register reg1,
Register reg2,
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 3247144..6fb7434 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -1394,6 +1394,10 @@
bind(&no_memento_found);
}
+ // Jumps to found label if a prototype map has dictionary elements.
+ void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
+ Register scratch1, Label* found);
+
private:
void CallCFunctionHelper(Register function,
int num_reg_arguments,
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 923011f..a7ddc8e 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -3020,10 +3020,7 @@
bool is_dont_delete) {
Label success, miss;
- __ CheckMap(
- receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
- HandlerFrontendHeader(
- object, receiver(), Handle<JSObject>::cast(global), name, &miss);
+ HandlerFrontendHeader(object, receiver(), global, name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(cell));
@@ -3045,7 +3042,7 @@
__ Ret();
// Return the generated code.
- return GetICCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), Code::NORMAL, name);
}
diff --git a/src/assembler.cc b/src/assembler.cc
index 0e05c2c..eb88922 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -826,7 +826,7 @@
PrintF(out, " (%s) (%p)", Code::Kind2String(code->kind()),
target_address());
if (rmode_ == CODE_TARGET_WITH_ID) {
- PrintF(" (id=%d)", static_cast<int>(data_));
+ PrintF(out, " (id=%d)", static_cast<int>(data_));
}
} else if (IsPosition(rmode_)) {
PrintF(out, " (%" V8_PTR_PREFIX "d)", data());
diff --git a/src/ast.cc b/src/ast.cc
index 843f8c8..9deb71d 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -256,6 +256,169 @@
}
+bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
+ return property != NULL &&
+ property->kind() != ObjectLiteral::Property::PROTOTYPE;
+}
+
+
+void ObjectLiteral::BuildConstantProperties(Isolate* isolate, int* depth) {
+ if (!constant_properties_.is_null()) return;
+
+ // Allocate a fixed array to hold all the constant properties.
+ Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray(
+ boilerplate_properties_ * 2, TENURED);
+
+ int position = 0;
+ // Accumulate the value in local variables and store it at the end.
+ bool is_simple = true;
+ int depth_acc = 1;
+ uint32_t max_element_index = 0;
+ uint32_t elements = 0;
+ for (int i = 0; i < properties()->length(); i++) {
+ ObjectLiteral::Property* property = properties()->at(i);
+ if (!IsBoilerplateProperty(property)) {
+ is_simple = false;
+ continue;
+ }
+ MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
+ if (m_literal != NULL) {
+ int inner_depth = 1;
+ m_literal->BuildConstants(isolate, &inner_depth);
+ if (inner_depth >= depth_acc) depth_acc = inner_depth + 1;
+ }
+
+ // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
+ // value for COMPUTED properties, the real value is filled in at
+ // runtime. The enumeration order is maintained.
+ Handle<Object> key = property->key()->value();
+ Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
+
+ // Ensure objects that may, at any point in time, contain fields with double
+ // representation are always treated as nested objects. This is true for
+ // computed fields (value is undefined), and smi and double literals
+ // (value->IsNumber()).
+ // TODO(verwaest): Remove once we can store them inline.
+ if (FLAG_track_double_fields &&
+ (value->IsNumber() || value->IsUninitialized())) {
+ may_store_doubles_ = true;
+ }
+
+ is_simple = is_simple && !value->IsUninitialized();
+
+ // Keep track of the number of elements in the object literal and
+ // the largest element index. If the largest element index is
+ // much larger than the number of elements, creating an object
+ // literal with fast elements will be a waste of space.
+ uint32_t element_index = 0;
+ if (key->IsString()
+ && Handle<String>::cast(key)->AsArrayIndex(&element_index)
+ && element_index > max_element_index) {
+ max_element_index = element_index;
+ elements++;
+ } else if (key->IsSmi()) {
+ int key_value = Smi::cast(*key)->value();
+ if (key_value > 0
+ && static_cast<uint32_t>(key_value) > max_element_index) {
+ max_element_index = key_value;
+ }
+ elements++;
+ }
+
+ // Add name, value pair to the fixed array.
+ constant_properties->set(position++, *key);
+ constant_properties->set(position++, *value);
+ }
+
+ constant_properties_ = constant_properties;
+ fast_elements_ =
+ (max_element_index <= 32) || ((2 * elements) >= max_element_index);
+ set_is_simple(is_simple);
+ if (depth != NULL) *depth = depth_acc;
+}
+
+
+void ArrayLiteral::BuildConstantElements(Isolate* isolate, int* depth) {
+ if (!constant_elements_.is_null()) return;
+
+ // Allocate a fixed array to hold all the object literals.
+ Handle<JSArray> array =
+ isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
+ isolate->factory()->SetElementsCapacityAndLength(
+ array, values()->length(), values()->length());
+
+ // Fill in the literals.
+ bool is_simple = true;
+ int depth_acc = 1;
+ bool is_holey = false;
+ for (int i = 0, n = values()->length(); i < n; i++) {
+ Expression* element = values()->at(i);
+ MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
+ if (m_literal != NULL) {
+ int inner_depth = 1;
+ m_literal->BuildConstants(isolate, &inner_depth);
+ if (inner_depth + 1 > depth_acc) depth_acc = inner_depth + 1;
+ }
+ Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
+ if (boilerplate_value->IsTheHole()) {
+ is_holey = true;
+ } else if (boilerplate_value->IsUninitialized()) {
+ is_simple = false;
+ JSObject::SetOwnElement(
+ array, i, handle(Smi::FromInt(0), isolate), kNonStrictMode);
+ } else {
+ JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode);
+ }
+ }
+
+ Handle<FixedArrayBase> element_values(array->elements());
+
+ // Simple and shallow arrays can be lazily copied, we transform the
+ // elements array to a copy-on-write array.
+ if (is_simple && depth_acc == 1 && values()->length() > 0 &&
+ array->HasFastSmiOrObjectElements()) {
+ element_values->set_map(isolate->heap()->fixed_cow_array_map());
+ }
+
+ // Remember both the literal's constant values as well as the ElementsKind
+ // in a 2-element FixedArray.
+ Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED);
+
+ ElementsKind kind = array->GetElementsKind();
+ kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
+
+ literals->set(0, Smi::FromInt(kind));
+ literals->set(1, *element_values);
+
+ constant_elements_ = literals;
+ set_is_simple(is_simple);
+ if (depth != NULL) *depth = depth_acc;
+}
+
+
+Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
+ Isolate* isolate) {
+ if (expression->AsLiteral() != NULL) {
+ return expression->AsLiteral()->value();
+ }
+ if (CompileTimeValue::IsCompileTimeValue(expression)) {
+ return CompileTimeValue::GetValue(isolate, expression);
+ }
+ return isolate->factory()->uninitialized_value();
+}
+
+
+void MaterializedLiteral::BuildConstants(Isolate* isolate, int* depth) {
+ if (IsArrayLiteral()) {
+ return AsArrayLiteral()->BuildConstantElements(isolate, depth);
+ }
+ if (IsObjectLiteral()) {
+ return AsObjectLiteral()->BuildConstantProperties(isolate, depth);
+ }
+ ASSERT(IsRegExpLiteral());
+}
+
+
void TargetCollector::AddTarget(Label* target, Zone* zone) {
// Add the label to the collector, but discard duplicates.
int length = targets_.length();
diff --git a/src/ast.h b/src/ast.h
index b4f7348..42f6c8b 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1409,27 +1409,35 @@
int literal_index() { return literal_index_; }
- // A materialized literal is simple if the values consist of only
- // constants and simple object and array literals.
- bool is_simple() const { return is_simple_; }
-
- int depth() const { return depth_; }
-
protected:
MaterializedLiteral(Isolate* isolate,
int literal_index,
- bool is_simple,
- int depth,
int pos)
: Expression(isolate, pos),
literal_index_(literal_index),
- is_simple_(is_simple),
- depth_(depth) {}
+ is_simple_(false) {}
+
+ // A materialized literal is simple if the values consist of only
+ // constants and simple object and array literals.
+ bool is_simple() const { return is_simple_; }
+ void set_is_simple(bool is_simple) { is_simple_ = is_simple; }
+ friend class CompileTimeValue;
+
+ // Populate the constant properties/elements fixed array.
+ void BuildConstants(Isolate* isolate, int* depth);
+ friend class ArrayLiteral;
+ friend class ObjectLiteral;
+
+ // If the expression is a literal, return the literal value;
+ // if the expression is a materialized literal and is simple return a
+ // compile time value as encoded by CompileTimeValue::GetValue().
+ // Otherwise, return undefined literal as the placeholder
+ // in the object literal boilerplate.
+ Handle<Object> GetBoilerplateValue(Expression* expression, Isolate* isolate);
private:
int literal_index_;
bool is_simple_;
- int depth_;
};
@@ -1493,6 +1501,12 @@
bool may_store_doubles() const { return may_store_doubles_; }
bool has_function() const { return has_function_; }
+ // Decide if a property should be in the object boilerplate.
+ static bool IsBoilerplateProperty(Property* property);
+
+ // Populate the constant properties fixed array.
+ void BuildConstantProperties(Isolate* isolate, int* depth = NULL);
+
// Mark all computed expressions that are bound to a key that
// is shadowed by a later occurrence of the same key. For the
// marked expressions, no store code is emitted.
@@ -1512,25 +1526,22 @@
protected:
ObjectLiteral(Isolate* isolate,
- Handle<FixedArray> constant_properties,
ZoneList<Property*>* properties,
int literal_index,
- bool is_simple,
- bool fast_elements,
- int depth,
- bool may_store_doubles,
+ int boilerplate_properties,
bool has_function,
int pos)
- : MaterializedLiteral(isolate, literal_index, is_simple, depth, pos),
- constant_properties_(constant_properties),
+ : MaterializedLiteral(isolate, literal_index, pos),
properties_(properties),
- fast_elements_(fast_elements),
- may_store_doubles_(may_store_doubles),
+ boilerplate_properties_(boilerplate_properties),
+ fast_elements_(false),
+ may_store_doubles_(false),
has_function_(has_function) {}
private:
Handle<FixedArray> constant_properties_;
ZoneList<Property*>* properties_;
+ int boilerplate_properties_;
bool fast_elements_;
bool may_store_doubles_;
bool has_function_;
@@ -1551,7 +1562,7 @@
Handle<String> flags,
int literal_index,
int pos)
- : MaterializedLiteral(isolate, literal_index, false, 1, pos),
+ : MaterializedLiteral(isolate, literal_index, pos),
pattern_(pattern),
flags_(flags) {}
@@ -1575,16 +1586,15 @@
return BailoutId(first_element_id_.ToInt() + i);
}
+ // Populate the constant elements fixed array.
+ void BuildConstantElements(Isolate* isolate, int* depth = NULL);
+
protected:
ArrayLiteral(Isolate* isolate,
- Handle<FixedArray> constant_elements,
ZoneList<Expression*>* values,
int literal_index,
- bool is_simple,
- int depth,
int pos)
- : MaterializedLiteral(isolate, literal_index, is_simple, depth, pos),
- constant_elements_(constant_elements),
+ : MaterializedLiteral(isolate, literal_index, pos),
values_(values),
first_element_id_(ReserveIdRange(isolate, values->length())) {}
@@ -3066,18 +3076,14 @@
}
ObjectLiteral* NewObjectLiteral(
- Handle<FixedArray> constant_properties,
ZoneList<ObjectLiteral::Property*>* properties,
int literal_index,
- bool is_simple,
- bool fast_elements,
- int depth,
- bool may_store_doubles,
+ int boilerplate_properties,
bool has_function,
int pos) {
ObjectLiteral* lit = new(zone_) ObjectLiteral(
- isolate_, constant_properties, properties, literal_index,
- is_simple, fast_elements, depth, may_store_doubles, has_function, pos);
+ isolate_, properties, literal_index, boilerplate_properties,
+ has_function, pos);
VISIT_AND_RETURN(ObjectLiteral, lit)
}
@@ -3099,15 +3105,11 @@
VISIT_AND_RETURN(RegExpLiteral, lit);
}
- ArrayLiteral* NewArrayLiteral(Handle<FixedArray> constant_elements,
- ZoneList<Expression*>* values,
+ ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
int literal_index,
- bool is_simple,
- int depth,
int pos) {
ArrayLiteral* lit = new(zone_) ArrayLiteral(
- isolate_, constant_elements, values, literal_index, is_simple,
- depth, pos);
+ isolate_, values, literal_index, pos);
VISIT_AND_RETURN(ArrayLiteral, lit)
}
diff --git a/src/builtins.cc b/src/builtins.cc
index b614904..758967e 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1750,9 +1750,10 @@
builtins_[i] = code;
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_builtin_code) {
- PrintF("Builtin: %s\n", functions[i].s_name);
- Code::cast(code)->Disassemble(functions[i].s_name);
- PrintF("\n");
+ CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
+ PrintF(trace_scope.file(), "Builtin: %s\n", functions[i].s_name);
+ Code::cast(code)->Disassemble(functions[i].s_name, trace_scope.file());
+ PrintF(trace_scope.file(), "\n");
}
#endif
} else {
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index dfa5ecd..19b6088 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -1241,8 +1241,6 @@
HObjectAccess::ForSharedFunctionInfoPointer(),
shared_info);
Add<HStoreNamedField>(js_function, HObjectAccess::ForFunctionContextPointer(),
- shared_info);
- Add<HStoreNamedField>(js_function, HObjectAccess::ForFunctionContextPointer(),
context());
// Initialize the code pointer in the function to be the one
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index e68a5dd..afa3cd0 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -160,8 +160,9 @@
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code_stubs) {
- new_object->Disassemble(*GetName());
- PrintF("\n");
+ CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
+ new_object->Disassemble(*GetName(), trace_scope.file());
+ PrintF(trace_scope.file(), "\n");
}
#endif
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 80d99d8..3dc32e8 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -553,51 +553,6 @@
int MinorKey() { return slots_; }
};
-class StoreGlobalStub : public HydrogenCodeStub {
- public:
- StoreGlobalStub(StrictModeFlag strict_mode, bool is_constant) {
- bit_field_ = StrictModeBits::encode(strict_mode) |
- IsConstantBits::encode(is_constant);
- }
-
- virtual Handle<Code> GenerateCode(Isolate* isolate);
-
- virtual void InitializeInterfaceDescriptor(
- Isolate* isolate,
- CodeStubInterfaceDescriptor* descriptor);
-
- virtual Code::Kind GetCodeKind() const { return Code::STORE_IC; }
- virtual InlineCacheState GetICState() { return MONOMORPHIC; }
- virtual Code::ExtraICState GetExtraICState() { return bit_field_; }
-
- bool is_constant() {
- return IsConstantBits::decode(bit_field_);
- }
- void set_is_constant(bool value) {
- bit_field_ = IsConstantBits::update(bit_field_, value);
- }
-
- Representation representation() {
- return Representation::FromKind(RepresentationBits::decode(bit_field_));
- }
- void set_representation(Representation r) {
- bit_field_ = RepresentationBits::update(bit_field_, r.kind());
- }
-
- private:
- virtual int NotMissMinorKey() { return GetExtraICState(); }
- Major MajorKey() { return StoreGlobal; }
-
- class StrictModeBits: public BitField<StrictModeFlag, 0, 1> {};
- class IsConstantBits: public BitField<bool, 1, 1> {};
- class RepresentationBits: public BitField<Representation::Kind, 2, 8> {};
-
- int bit_field_;
-
- DISALLOW_COPY_AND_ASSIGN(StoreGlobalStub);
-};
-
-
class FastCloneShallowArrayStub : public HydrogenCodeStub {
public:
// Maximum length of copied elements array.
@@ -899,7 +854,6 @@
virtual InlineCacheState GetICState() { return MONOMORPHIC; }
protected:
- HICStub() { }
class KindBits: public BitField<Code::Kind, 0, 4> {};
virtual Code::Kind kind() const = 0;
};
@@ -909,16 +863,12 @@
public:
virtual Code::Kind GetCodeKind() const { return Code::HANDLER; }
virtual int GetStubFlags() { return kind(); }
-
- protected:
- HandlerStub() : HICStub() { }
};
class LoadFieldStub: public HandlerStub {
public:
- LoadFieldStub(bool inobject, int index, Representation representation)
- : HandlerStub() {
+ LoadFieldStub(bool inobject, int index, Representation representation) {
Initialize(Code::LOAD_IC, inobject, index, representation);
}
@@ -980,6 +930,63 @@
};
+class StoreGlobalStub : public HandlerStub {
+ public:
+ StoreGlobalStub(StrictModeFlag strict_mode, bool is_constant) {
+ bit_field_ = StrictModeBits::encode(strict_mode) |
+ IsConstantBits::encode(is_constant);
+ }
+
+ Handle<Code> GetCodeCopyFromTemplate(Isolate* isolate,
+ Map* receiver_map,
+ PropertyCell* cell) {
+ Handle<Code> code = CodeStub::GetCodeCopyFromTemplate(isolate);
+ // Replace the placeholder cell and global object map with the actual global
+ // cell and receiver map.
+ Map* cell_map = isolate->heap()->global_property_cell_map();
+ code->ReplaceNthObject(1, cell_map, cell);
+ code->ReplaceNthObject(1, isolate->heap()->meta_map(), receiver_map);
+ return code;
+ }
+
+ virtual Code::Kind kind() const { return Code::STORE_IC; }
+
+ virtual Handle<Code> GenerateCode(Isolate* isolate);
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
+ virtual Code::ExtraICState GetExtraICState() { return bit_field_; }
+
+ bool is_constant() {
+ return IsConstantBits::decode(bit_field_);
+ }
+ void set_is_constant(bool value) {
+ bit_field_ = IsConstantBits::update(bit_field_, value);
+ }
+
+ Representation representation() {
+ return Representation::FromKind(RepresentationBits::decode(bit_field_));
+ }
+ void set_representation(Representation r) {
+ bit_field_ = RepresentationBits::update(bit_field_, r.kind());
+ }
+
+ private:
+ virtual int NotMissMinorKey() { return GetExtraICState(); }
+ Major MajorKey() { return StoreGlobal; }
+
+ class StrictModeBits: public BitField<StrictModeFlag, 0, 1> {};
+ class IsConstantBits: public BitField<bool, 1, 1> {};
+ class RepresentationBits: public BitField<Representation::Kind, 2, 8> {};
+
+ int bit_field_;
+
+ DISALLOW_COPY_AND_ASSIGN(StoreGlobalStub);
+};
+
+
class KeyedLoadFieldStub: public LoadFieldStub {
public:
KeyedLoadFieldStub(bool inobject, int index, Representation representation)
diff --git a/src/codegen.cc b/src/codegen.cc
index 573ddc6..28f7d6c 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -136,10 +136,12 @@
FunctionLiteral* function = info->function();
bool print_source = code->kind() == Code::OPTIMIZED_FUNCTION ||
code->kind() == Code::FUNCTION;
+
+ CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
if (print_source) {
Handle<Script> script = info->script();
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
- PrintF("--- Raw source ---\n");
+ PrintF(tracing_scope.file(), "--- Raw source ---\n");
ConsStringIteratorOp op;
StringCharacterStream stream(String::cast(script->source()),
&op,
@@ -149,31 +151,36 @@
int source_len =
function->end_position() - function->start_position() + 1;
for (int i = 0; i < source_len; i++) {
- if (stream.HasMore()) PrintF("%c", stream.GetNext());
+ if (stream.HasMore()) {
+ PrintF(tracing_scope.file(), "%c", stream.GetNext());
+ }
}
- PrintF("\n\n");
+ PrintF(tracing_scope.file(), "\n\n");
}
}
if (info->IsOptimizing()) {
if (FLAG_print_unopt_code) {
- PrintF("--- Unoptimized code ---\n");
+ PrintF(tracing_scope.file(), "--- Unoptimized code ---\n");
info->closure()->shared()->code()->Disassemble(
- *function->debug_name()->ToCString());
+ *function->debug_name()->ToCString(), tracing_scope.file());
}
- PrintF("--- Optimized code ---\n");
+ PrintF(tracing_scope.file(), "--- Optimized code ---\n");
} else {
- PrintF("--- Code ---\n");
+ PrintF(tracing_scope.file(), "--- Code ---\n");
}
if (print_source) {
- PrintF("source_position = %d\n", function->start_position());
+ PrintF(tracing_scope.file(),
+ "source_position = %d\n", function->start_position());
}
if (info->IsStub()) {
CodeStub::Major major_key = info->code_stub()->MajorKey();
- code->Disassemble(CodeStub::MajorName(major_key, false));
+ code->Disassemble(CodeStub::MajorName(major_key, false),
+ tracing_scope.file());
} else {
- code->Disassemble(*function->debug_name()->ToCString());
+ code->Disassemble(*function->debug_name()->ToCString(),
+ tracing_scope.file());
}
- PrintF("--- End code ---\n");
+ PrintF(tracing_scope.file(), "--- End code ---\n");
}
#endif // ENABLE_DISASSEMBLER
}
diff --git a/src/compiler.cc b/src/compiler.cc
index ed0a0c8..e86baa0 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -262,8 +262,11 @@
void RecompileJob::RecordOptimizationStats() {
Handle<JSFunction> function = info()->closure();
- int opt_count = function->shared()->opt_count();
- function->shared()->set_opt_count(opt_count + 1);
+ if (!function->IsOptimized()) {
+ // Concurrent recompilation and OSR may race. Increment only once.
+ int opt_count = function->shared()->opt_count();
+ function->shared()->set_opt_count(opt_count + 1);
+ }
double ms_creategraph = time_taken_to_create_graph_.InMillisecondsF();
double ms_optimize = time_taken_to_optimize_.InMillisecondsF();
double ms_codegen = time_taken_to_codegen_.InMillisecondsF();
diff --git a/src/d8.cc b/src/d8.cc
index 357c8a4..17bd671 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1585,6 +1585,7 @@
char **fake_argv = new char*[2];
fake_argv[0] = NULL;
fake_argv[1] = strdup("--trace-hydrogen-file=hydrogen.cfg");
+ fake_argv[2] = strdup("--redirect-code-traces-to=code.asm");
v8::V8::SetFlagsFromCommandLine(&fake_argc, fake_argv, false);
free(fake_argv[1]);
delete[] fake_argv;
@@ -1674,6 +1675,7 @@
v8::V8::InitializeICU();
#ifndef V8_SHARED
i::FLAG_trace_hydrogen_file = "hydrogen.cfg";
+ i::FLAG_redirect_code_traces_to = "code.asm";
#else
SetStandaloneFlagsViaCommandLine();
#endif
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 96871d6..4f2cd03 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -344,9 +344,11 @@
shared->EvictFromOptimizedCodeMap(code, "deoptimized function");
if (FLAG_trace_deopt) {
- PrintF("[deoptimizer unlinked: ");
- function->PrintName();
- PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
+ CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
+ PrintF(scope.file(), "[deoptimizer unlinked: ");
+ function->PrintName(scope.file());
+ PrintF(scope.file(),
+ " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
}
}
};
@@ -409,7 +411,8 @@
void Deoptimizer::DeoptimizeAll(Isolate* isolate) {
if (FLAG_trace_deopt) {
- PrintF("[deoptimize all code in all contexts]\n");
+ CodeTracer::Scope scope(isolate->GetCodeTracer());
+ PrintF(scope.file(), "[deoptimize all code in all contexts]\n");
}
DisallowHeapAllocation no_allocation;
// For all contexts, mark all code, then deoptimize.
@@ -425,7 +428,8 @@
void Deoptimizer::DeoptimizeMarkedCode(Isolate* isolate) {
if (FLAG_trace_deopt) {
- PrintF("[deoptimize marked code in all contexts]\n");
+ CodeTracer::Scope scope(isolate->GetCodeTracer());
+ PrintF(scope.file(), "[deoptimize marked code in all contexts]\n");
}
DisallowHeapAllocation no_allocation;
// For all contexts, deoptimize code already marked.
@@ -440,7 +444,8 @@
void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
if (FLAG_trace_deopt) {
- PrintF("[deoptimize global object @ 0x%08" V8PRIxPTR "]\n",
+ CodeTracer::Scope scope(object->GetHeap()->isolate()->GetCodeTracer());
+ PrintF(scope.file(), "[deoptimize global object @ 0x%08" V8PRIxPTR "]\n",
reinterpret_cast<intptr_t>(object));
}
if (object->IsJSGlobalProxy()) {
@@ -541,7 +546,7 @@
materialized_objects_(NULL),
materialization_value_index_(0),
materialization_object_index_(0),
- trace_(false) {
+ trace_scope_(NULL) {
// For COMPILED_STUBs called from builtins, the function pointer is a SMI
// indicating an internal frame.
if (function->IsSmi()) {
@@ -571,7 +576,8 @@
StackFrame::Type frame_type = function == NULL
? StackFrame::STUB
: StackFrame::JAVA_SCRIPT;
- trace_ = TraceEnabledFor(type, frame_type);
+ trace_scope_ = TraceEnabledFor(type, frame_type) ?
+ new CodeTracer::Scope(isolate->GetCodeTracer()) : NULL;
#ifdef DEBUG
CHECK(AllowHeapAllocation::IsAllowed());
disallow_heap_allocation_ = new DisallowHeapAllocation();
@@ -604,9 +610,10 @@
void Deoptimizer::PrintFunctionName() {
if (function_->IsJSFunction()) {
- function_->PrintName();
+ function_->PrintName(trace_scope_->file());
} else {
- PrintF("%s", Code::Kind2String(compiled_code_->kind()));
+ PrintF(trace_scope_->file(),
+ "%s", Code::Kind2String(compiled_code_->kind()));
}
}
@@ -614,6 +621,7 @@
Deoptimizer::~Deoptimizer() {
ASSERT(input_ == NULL && output_ == NULL);
ASSERT(disallow_heap_allocation_ == NULL);
+ delete trace_scope_;
}
@@ -681,13 +689,13 @@
return data->PcAndState(i)->value();
}
}
- PrintF("[couldn't find pc offset for node=%d]\n", id.ToInt());
- PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
+ PrintF(stderr, "[couldn't find pc offset for node=%d]\n", id.ToInt());
+ PrintF(stderr, "[method: %s]\n", *shared->DebugName()->ToCString());
// Print the source code if available.
HeapStringAllocator string_allocator;
StringStream stream(&string_allocator);
shared->SourceCodePrint(&stream, -1);
- PrintF("[source:\n%s\n]", *stream.ToCString());
+ PrintF(stderr, "[source:\n%s\n]", *stream.ToCString());
FATAL("unable to find pc offset during deoptimization");
return -1;
@@ -722,15 +730,19 @@
LOG(isolate(), CodeDeoptEvent(compiled_code_));
}
ElapsedTimer timer;
- if (trace_) {
+ if (trace_scope_ != NULL) {
timer.Start();
- PrintF("[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
+ PrintF(trace_scope_->file(),
+ "[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
MessageFor(bailout_type_),
reinterpret_cast<intptr_t>(function_));
PrintFunctionName();
- PrintF(" @%d, FP to SP delta: %d]\n", bailout_id_, fp_to_sp_delta_);
+ PrintF(trace_scope_->file(),
+ " @%d, FP to SP delta: %d]\n",
+ bailout_id_,
+ fp_to_sp_delta_);
if (bailout_type_ == EAGER || bailout_type_ == SOFT) {
- compiled_code_->PrintDeoptLocation(bailout_id_);
+ compiled_code_->PrintDeoptLocation(trace_scope_->file(), bailout_id_);
}
}
@@ -803,15 +815,17 @@
}
// Print some helpful diagnostic information.
- if (trace_) {
+ if (trace_scope_ != NULL) {
double ms = timer.Elapsed().InMillisecondsF();
int index = output_count_ - 1; // Index of the topmost frame.
JSFunction* function = output_[index]->GetFunction();
- PrintF("[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
+ PrintF(trace_scope_->file(),
+ "[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
MessageFor(bailout_type_),
reinterpret_cast<intptr_t>(function));
PrintFunctionName();
- PrintF(" @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
+ PrintF(trace_scope_->file(),
+ " @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
" took %0.3f ms]\n",
bailout_id_,
node_id.ToInt(),
@@ -839,10 +853,11 @@
}
unsigned height = iterator->Next();
unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating ");
- function->PrintName();
- PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(), " translating ");
+ function->PrintName(trace_scope_->file());
+ PrintF(trace_scope_->file(),
+ " => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
}
// The 'fixed' part of the frame consists of the incoming parameters and
@@ -909,8 +924,9 @@
value = output_[frame_index - 1]->GetPc();
}
output_frame->SetCallerPc(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; caller's pc\n",
top_address + output_offset, output_offset, value);
}
@@ -932,8 +948,9 @@
has_alignment_padding_ * kPointerSize) == fp_value);
output_frame->SetFp(fp_value);
if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; caller's fp\n",
fp_value, output_offset, value);
}
@@ -954,8 +971,9 @@
output_frame->SetFrameSlot(output_offset, value);
output_frame->SetContext(value);
if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR "; context\n",
top_address + output_offset, output_offset, value);
}
@@ -968,8 +986,9 @@
// input frame.
ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR "; function\n",
top_address + output_offset, output_offset, value);
}
@@ -1017,8 +1036,9 @@
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
unsigned height = iterator->Next();
unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " translating arguments adaptor => height=%d\n", height_in_bytes);
}
unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
@@ -1052,8 +1072,9 @@
output_offset -= kPCOnStackSize;
intptr_t callers_pc = output_[frame_index - 1]->GetPc();
output_frame->SetCallerPc(output_offset, callers_pc);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; caller's pc\n",
top_address + output_offset, output_offset, callers_pc);
}
@@ -1064,8 +1085,9 @@
output_frame->SetCallerFp(output_offset, value);
intptr_t fp_value = top_address + output_offset;
output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; caller's fp\n",
fp_value, output_offset, value);
}
@@ -1075,8 +1097,9 @@
intptr_t context = reinterpret_cast<intptr_t>(
Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
output_frame->SetFrameSlot(output_offset, context);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; context (adaptor sentinel)\n",
top_address + output_offset, output_offset, context);
}
@@ -1085,8 +1108,9 @@
output_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(function);
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; function\n",
top_address + output_offset, output_offset, value);
}
@@ -1095,8 +1119,9 @@
output_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; argc (%d)\n",
top_address + output_offset, output_offset, value, height - 1);
}
@@ -1120,8 +1145,9 @@
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
unsigned height = iterator->Next();
unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating construct stub => height=%d\n", height_in_bytes);
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " translating construct stub => height=%d\n", height_in_bytes);
}
unsigned fixed_frame_size = ConstructFrameConstants::kFrameSize;
@@ -1163,8 +1189,9 @@
output_offset -= kPCOnStackSize;
intptr_t callers_pc = output_[frame_index - 1]->GetPc();
output_frame->SetCallerPc(output_offset, callers_pc);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; caller's pc\n",
top_address + output_offset, output_offset, callers_pc);
}
@@ -1175,8 +1202,9 @@
output_frame->SetCallerFp(output_offset, value);
intptr_t fp_value = top_address + output_offset;
output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; caller's fp\n",
fp_value, output_offset, value);
}
@@ -1185,8 +1213,9 @@
output_offset -= kPointerSize;
value = output_[frame_index - 1]->GetContext();
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; context\n",
top_address + output_offset, output_offset, value);
}
@@ -1195,8 +1224,9 @@
output_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; function (construct sentinel)\n",
top_address + output_offset, output_offset, value);
}
@@ -1205,8 +1235,9 @@
output_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(construct_stub);
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; code object\n",
top_address + output_offset, output_offset, value);
}
@@ -1215,8 +1246,9 @@
output_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; argc (%d)\n",
top_address + output_offset, output_offset, value, height - 1);
}
@@ -1227,8 +1259,9 @@
output_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(function);
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; constructor function\n",
top_address + output_offset, output_offset, value);
}
@@ -1239,8 +1272,9 @@
output_offset -= kPointerSize;
value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; allocated receiver\n",
top_address + output_offset, output_offset, value);
}
@@ -1264,8 +1298,9 @@
unsigned height = 0;
unsigned height_in_bytes = height * kPointerSize;
const char* kind = is_setter_stub_frame ? "setter" : "getter";
- if (trace_) {
- PrintF(" translating %s stub => height=%u\n", kind, height_in_bytes);
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " translating %s stub => height=%u\n", kind, height_in_bytes);
}
// We need 1 stack entry for the return address + 4 stack entries from
@@ -1300,8 +1335,9 @@
output_offset -= kPCOnStackSize;
intptr_t callers_pc = output_[frame_index - 1]->GetPc();
output_frame->SetCallerPc(output_offset, callers_pc);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
" ; caller's pc\n",
top_address + output_offset, output_offset, callers_pc);
}
@@ -1312,8 +1348,9 @@
output_frame->SetCallerFp(output_offset, value);
intptr_t fp_value = top_address + output_offset;
output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
" ; caller's fp\n",
fp_value, output_offset, value);
}
@@ -1322,8 +1359,9 @@
output_offset -= kPointerSize;
value = output_[frame_index - 1]->GetContext();
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
" ; context\n",
top_address + output_offset, output_offset, value);
}
@@ -1332,8 +1370,9 @@
output_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
" ; function (%s sentinel)\n",
top_address + output_offset, output_offset, value, kind);
}
@@ -1346,8 +1385,9 @@
Code* accessor_stub = isolate_->builtins()->builtin(name);
value = reinterpret_cast<intptr_t>(accessor_stub);
output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
" ; code object\n",
top_address + output_offset, output_offset, value);
}
@@ -1423,8 +1463,9 @@
int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
int input_frame_size = input_->GetFrameSize();
int output_frame_size = height_in_bytes + fixed_frame_size;
- if (trace_) {
- PrintF(" translating %s => StubFailureTrampolineStub, height=%d\n",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " translating %s => StubFailureTrampolineStub, height=%d\n",
CodeStub::MajorName(static_cast<CodeStub::Major>(major_key), false),
height_in_bytes);
}
@@ -1449,8 +1490,9 @@
unsigned output_frame_offset = output_frame_size - kFPOnStackSize;
intptr_t value = input_->GetFrameSlot(input_frame_offset);
output_frame->SetCallerPc(output_frame_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; caller's pc\n",
top_address + output_frame_offset, output_frame_offset, value);
}
@@ -1463,8 +1505,9 @@
intptr_t frame_ptr = input_->GetRegister(fp_reg.code());
output_frame->SetRegister(fp_reg.code(), frame_ptr);
output_frame->SetFp(frame_ptr);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; caller's fp\n",
top_address + output_frame_offset, output_frame_offset, value);
}
@@ -1476,8 +1519,9 @@
output_frame->SetRegister(context_reg.code(), value);
output_frame_offset -= kPointerSize;
output_frame->SetFrameSlot(output_frame_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; context\n",
top_address + output_frame_offset, output_frame_offset, value);
}
@@ -1487,8 +1531,9 @@
value = reinterpret_cast<intptr_t>(
Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
output_frame->SetFrameSlot(output_frame_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; function (stub failure sentinel)\n",
top_address + output_frame_offset, output_frame_offset, value);
}
@@ -1509,8 +1554,9 @@
}
output_frame->SetFrameSlot(args_arguments_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; args.arguments %s\n",
top_address + args_arguments_offset, args_arguments_offset, value,
arg_count_known ? "" : "(the hole)");
@@ -1520,8 +1566,9 @@
int length_frame_offset = output_frame_offset;
value = arg_count_known ? caller_arg_count : the_hole;
output_frame->SetFrameSlot(length_frame_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; args.length %s\n",
top_address + length_frame_offset, length_frame_offset, value,
arg_count_known ? "" : "(the hole)");
@@ -1531,8 +1578,9 @@
value = frame_ptr + StandardFrameConstants::kCallerSPOffset -
(output_frame_size - output_frame_offset) + kPointerSize;
output_frame->SetFrameSlot(output_frame_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; args*\n",
top_address + output_frame_offset, output_frame_offset, value);
}
@@ -1550,8 +1598,9 @@
value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
(caller_arg_count - 1) * kPointerSize;
output_frame->SetFrameSlot(args_arguments_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; args.arguments\n",
top_address + args_arguments_offset, args_arguments_offset, value);
}
@@ -1654,7 +1703,8 @@
break;
}
default:
- PrintF("[couldn't handle instance type %d]\n", map->instance_type());
+ PrintF(stderr,
+ "[couldn't handle instance type %d]\n", map->instance_type());
UNREACHABLE();
}
}
@@ -1699,8 +1749,9 @@
for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
HeapNumberMaterializationDescriptor<Address> d = deferred_heap_numbers_[i];
Handle<Object> num = isolate_->factory()->NewNumber(d.value());
- if (trace_) {
- PrintF("Materialized a new heap number %p [%e] in slot %p\n",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ "Materialized a new heap number %p [%e] in slot %p\n",
reinterpret_cast<void*>(*num),
d.value(),
d.destination());
@@ -1713,8 +1764,9 @@
HeapNumberMaterializationDescriptor<int> d =
deferred_objects_double_values_[i];
Handle<Object> num = isolate_->factory()->NewNumber(d.value());
- if (trace_) {
- PrintF("Materialized a new heap number %p [%e] for object at %d\n",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ "Materialized a new heap number %p [%e] for object at %d\n",
reinterpret_cast<void*>(*num),
d.value(),
d.destination());
@@ -1742,19 +1794,21 @@
// the materialized object into the frame slot.
Handle<Object> object = MaterializeNextHeapObject();
Memory::Object_at(descriptor.slot_address()) = *object;
- if (trace_) {
+ if (trace_scope_ != NULL) {
if (descriptor.is_arguments()) {
- PrintF("Materialized %sarguments object of length %d for %p: ",
+ PrintF(trace_scope_->file(),
+ "Materialized %sarguments object of length %d for %p: ",
ArgumentsObjectIsAdapted(object_index) ? "(adapted) " : "",
Handle<JSObject>::cast(object)->elements()->length(),
reinterpret_cast<void*>(descriptor.slot_address()));
} else {
- PrintF("Materialized captured object of size %d for %p: ",
+ PrintF(trace_scope_->file(),
+ "Materialized captured object of size %d for %p: ",
Handle<HeapObject>::cast(object)->Size(),
reinterpret_cast<void*>(descriptor.slot_address()));
}
- object->ShortPrint();
- PrintF("\n");
+ object->ShortPrint(trace_scope_->file());
+ PrintF(trace_scope_->file(), "\n");
}
}
@@ -1786,8 +1840,9 @@
int index = (info->parameters_count() - 1) -
static_cast<int>(slot - parameters_top) / kPointerSize;
- if (trace_) {
- PrintF("Materializing a new heap number %p [%e] in slot %p"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ "Materializing a new heap number %p [%e] in slot %p"
"for parameter slot #%d\n",
reinterpret_cast<void*>(*num),
d.value(),
@@ -1802,8 +1857,9 @@
int index = info->expression_count() - 1 -
static_cast<int>(slot - expressions_top) / kPointerSize;
- if (trace_) {
- PrintF("Materializing a new heap number %p [%e] in slot %p"
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ "Materializing a new heap number %p [%e] in slot %p"
"for expression slot #%d\n",
reinterpret_cast<void*>(*num),
d.value(),
@@ -1852,14 +1908,18 @@
case Translation::REGISTER: {
int input_reg = iterator->Next();
intptr_t input_value = input_->GetRegister(input_reg);
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- PrintF("0x%08" V8PRIxPTR " ; %s ", input_value,
+ PrintF(trace_scope_->file(),
+ "0x%08" V8PRIxPTR " ; %s ", input_value,
converter.NameOfCPURegister(input_reg));
- reinterpret_cast<Object*>(input_value)->ShortPrint();
- PrintF("\n");
+ reinterpret_cast<Object*>(input_value)->ShortPrint(
+ trace_scope_->file());
+ PrintF(trace_scope_->file(),
+ "\n");
}
AddObjectTaggedValue(input_value);
return;
@@ -1869,11 +1929,13 @@
int input_reg = iterator->Next();
intptr_t value = input_->GetRegister(input_reg);
bool is_smi = Smi::IsValid(value);
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- PrintF("%" V8PRIdPTR " ; %s (%s)\n", value,
+ PrintF(trace_scope_->file(),
+ "%" V8PRIdPTR " ; %s (%s)\n", value,
converter.NameOfCPURegister(input_reg),
TraceValueType(is_smi));
}
@@ -1892,11 +1954,13 @@
int input_reg = iterator->Next();
uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- PrintF("%" V8PRIdPTR " ; uint %s (%s)\n", value,
+ PrintF(trace_scope_->file(),
+ "%" V8PRIdPTR " ; uint %s (%s)\n", value,
converter.NameOfCPURegister(input_reg),
TraceValueType(is_smi));
}
@@ -1914,11 +1978,13 @@
case Translation::DOUBLE_REGISTER: {
int input_reg = iterator->Next();
double value = input_->GetDoubleRegister(input_reg);
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- PrintF("%e ; %s\n", value,
+ PrintF(trace_scope_->file(),
+ "%e ; %s\n", value,
DoubleRegister::AllocationIndexToString(input_reg));
}
AddObjectDoubleValue(value);
@@ -1929,13 +1995,17 @@
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t input_value = input_->GetFrameSlot(input_offset);
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- PrintF("0x%08" V8PRIxPTR " ; [sp + %d] ", input_value, input_offset);
- reinterpret_cast<Object*>(input_value)->ShortPrint();
- PrintF("\n");
+ PrintF(trace_scope_->file(),
+ "0x%08" V8PRIxPTR " ; [sp + %d] ", input_value, input_offset);
+ reinterpret_cast<Object*>(input_value)->ShortPrint(
+ trace_scope_->file());
+ PrintF(trace_scope_->file(),
+ "\n");
}
AddObjectTaggedValue(input_value);
return;
@@ -1946,11 +2016,13 @@
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t value = input_->GetFrameSlot(input_offset);
bool is_smi = Smi::IsValid(value);
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- PrintF("%" V8PRIdPTR " ; [sp + %d] (%s)\n",
+ PrintF(trace_scope_->file(),
+ "%" V8PRIdPTR " ; [sp + %d] (%s)\n",
value, input_offset, TraceValueType(is_smi));
}
if (is_smi) {
@@ -1970,11 +2042,13 @@
uintptr_t value =
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- PrintF("%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
+ PrintF(trace_scope_->file(),
+ "%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
value, input_offset, TraceValueType(is_smi));
}
if (is_smi) {
@@ -1992,11 +2066,13 @@
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
double value = input_->GetDoubleFrameSlot(input_offset);
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- PrintF("%e ; [sp + %d]\n", value, input_offset);
+ PrintF(trace_scope_->file(),
+ "%e ; [sp + %d]\n", value, input_offset);
}
AddObjectDoubleValue(value);
return;
@@ -2004,12 +2080,14 @@
case Translation::LITERAL: {
Object* literal = ComputeLiteral(iterator->Next());
- if (trace_) {
- PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- literal->ShortPrint();
- PrintF(" ; literal\n");
+ literal->ShortPrint(trace_scope_->file());
+ PrintF(trace_scope_->file(),
+ " ; literal\n");
}
intptr_t value = reinterpret_cast<intptr_t>(literal);
AddObjectTaggedValue(value);
@@ -2018,12 +2096,14 @@
case Translation::DUPLICATED_OBJECT: {
int object_index = iterator->Next();
- if (trace_) {
- PrintF(" nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- isolate_->heap()->arguments_marker()->ShortPrint();
- PrintF(" ; duplicate of object #%d\n", object_index);
+ isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
+ PrintF(trace_scope_->file(),
+ " ; duplicate of object #%d\n", object_index);
}
// Use the materialization marker value as a sentinel and fill in
// the object after the deoptimized frame is built.
@@ -2038,12 +2118,14 @@
case Translation::CAPTURED_OBJECT: {
int length = iterator->Next();
bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
- if (trace_) {
- PrintF(" nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
- isolate_->heap()->arguments_marker()->ShortPrint();
- PrintF(" ; object (length = %d, is_args = %d)\n", length, is_args);
+ isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
+ PrintF(trace_scope_->file(),
+ " ; object (length = %d, is_args = %d)\n", length, is_args);
}
// Use the materialization marker value as a sentinel and fill in
// the object after the deoptimized frame is built.
@@ -2089,15 +2171,17 @@
case Translation::REGISTER: {
int input_reg = iterator->Next();
intptr_t input_value = input_->GetRegister(input_reg);
- if (trace_) {
+ if (trace_scope_ != NULL) {
PrintF(
+ trace_scope_->file(),
" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
output_[frame_index]->GetTop() + output_offset,
output_offset,
input_value,
converter.NameOfCPURegister(input_reg));
- reinterpret_cast<Object*>(input_value)->ShortPrint();
- PrintF("\n");
+ reinterpret_cast<Object*>(input_value)->ShortPrint(
+ trace_scope_->file());
+ PrintF(trace_scope_->file(), "\n");
}
output_[frame_index]->SetFrameSlot(output_offset, input_value);
return;
@@ -2108,8 +2192,9 @@
intptr_t value = input_->GetRegister(input_reg);
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
Smi::IsValid(value);
- if (trace_) {
+ if (trace_scope_ != NULL) {
PrintF(
+ trace_scope_->file(),
" 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
output_[frame_index]->GetTop() + output_offset,
output_offset,
@@ -2139,8 +2224,9 @@
uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
(value <= static_cast<uintptr_t>(Smi::kMaxValue));
- if (trace_) {
+ if (trace_scope_ != NULL) {
PrintF(
+ trace_scope_->file(),
" 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR
" ; uint %s (%s)\n",
output_[frame_index]->GetTop() + output_offset,
@@ -2169,8 +2255,9 @@
case Translation::DOUBLE_REGISTER: {
int input_reg = iterator->Next();
double value = input_->GetDoubleRegister(input_reg);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
output_[frame_index]->GetTop() + output_offset,
output_offset,
value,
@@ -2187,15 +2274,18 @@
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t input_value = input_->GetFrameSlot(input_offset);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset);
- PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
+ PrintF(trace_scope_->file(),
+ "[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
output_offset,
input_value,
input_offset);
- reinterpret_cast<Object*>(input_value)->ShortPrint();
- PrintF("\n");
+ reinterpret_cast<Object*>(input_value)->ShortPrint(
+ trace_scope_->file());
+ PrintF(trace_scope_->file(), "\n");
}
output_[frame_index]->SetFrameSlot(output_offset, input_value);
return;
@@ -2207,10 +2297,12 @@
intptr_t value = input_->GetFrameSlot(input_offset);
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
Smi::IsValid(value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset);
- PrintF("[top + %d] <- %" V8PRIdPTR " ; [sp + %d] (%s)\n",
+ PrintF(trace_scope_->file(),
+ "[top + %d] <- %" V8PRIdPTR " ; [sp + %d] (%s)\n",
output_offset,
value,
input_offset,
@@ -2240,10 +2332,12 @@
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
(value <= static_cast<uintptr_t>(Smi::kMaxValue));
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset);
- PrintF("[top + %d] <- %" V8PRIuPTR " ; [sp + %d] (uint32 %s)\n",
+ PrintF(trace_scope_->file(),
+ "[top + %d] <- %" V8PRIuPTR " ; [sp + %d] (uint32 %s)\n",
output_offset,
value,
input_offset,
@@ -2270,8 +2364,9 @@
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
double value = input_->GetDoubleFrameSlot(input_offset);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
output_[frame_index]->GetTop() + output_offset,
output_offset,
value,
@@ -2286,12 +2381,13 @@
case Translation::LITERAL: {
Object* literal = ComputeLiteral(iterator->Next());
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
output_offset);
- literal->ShortPrint();
- PrintF(" ; literal\n");
+ literal->ShortPrint(trace_scope_->file());
+ PrintF(trace_scope_->file(), " ; literal\n");
}
intptr_t value = reinterpret_cast<intptr_t>(literal);
output_[frame_index]->SetFrameSlot(output_offset, value);
@@ -2300,12 +2396,14 @@
case Translation::DUPLICATED_OBJECT: {
int object_index = iterator->Next();
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
output_offset);
- isolate_->heap()->arguments_marker()->ShortPrint();
- PrintF(" ; duplicate of object #%d\n", object_index);
+ isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
+ PrintF(trace_scope_->file(),
+ " ; duplicate of object #%d\n", object_index);
}
// Use the materialization marker value as a sentinel and fill in
// the object after the deoptimized frame is built.
@@ -2321,12 +2419,14 @@
case Translation::CAPTURED_OBJECT: {
int length = iterator->Next();
bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
output_offset);
- isolate_->heap()->arguments_marker()->ShortPrint();
- PrintF(" ; object (length = %d, is_args = %d)\n", length, is_args);
+ isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
+ PrintF(trace_scope_->file(),
+ " ; object (length = %d, is_args = %d)\n", length, is_args);
}
// Use the materialization marker value as a sentinel and fill in
// the object after the deoptimized frame is built.
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 4e9d281..f5530a8 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -451,7 +451,7 @@
DisallowHeapAllocation* disallow_heap_allocation_;
#endif // DEBUG
- bool trace_;
+ CodeTracer::Scope* trace_scope_;
static const int table_entry_size_;
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 9228944..f0444d1 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -795,6 +795,12 @@
DEFINE_implication(log_timer_events, log_internal_timer_events)
DEFINE_implication(log_internal_timer_events, prof)
+DEFINE_bool(redirect_code_traces, false,
+ "output deopt information and disassembly into file "
+ "code-<pid>-<isolate id>.asm")
+DEFINE_string(redirect_code_traces_to, NULL,
+ "output deopt information and disassembly into the given file")
+
//
// Disassembler only flags
//
diff --git a/src/func-name-inferrer.cc b/src/func-name-inferrer.cc
index 84d3bf0..5409a4e 100644
--- a/src/func-name-inferrer.cc
+++ b/src/func-name-inferrer.cc
@@ -62,7 +62,7 @@
void FuncNameInferrer::PushVariableName(Handle<String> name) {
- if (IsOpen() && !isolate()->heap()->result_string()->Equals(*name)) {
+ if (IsOpen() && !isolate()->heap()->dot_result_string()->Equals(*name)) {
names_stack_.Add(Name(name, kVariableName), zone());
}
}
diff --git a/src/handles.cc b/src/handles.cc
index f3928eb..6fd047b 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -160,30 +160,12 @@
}
-Handle<Object> SetProperty(Isolate* isolate,
- Handle<Object> object,
- Handle<Object> key,
- Handle<Object> value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode) {
- CALL_HEAP_FUNCTION(
- isolate,
- Runtime::SetObjectProperty(
- isolate, object, key, value, attributes, strict_mode),
- Object);
-}
-
-
Handle<Object> ForceSetProperty(Handle<JSObject> object,
Handle<Object> key,
Handle<Object> value,
PropertyAttributes attributes) {
- Isolate* isolate = object->GetIsolate();
- CALL_HEAP_FUNCTION(
- isolate,
- Runtime::ForceSetObjectProperty(
- isolate, object, key, value, attributes),
- Object);
+ return Runtime::ForceSetObjectProperty(object->GetIsolate(), object, key,
+ value, attributes);
}
diff --git a/src/handles.h b/src/handles.h
index 890f4f5..5bc5779 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -228,13 +228,6 @@
// string.
Handle<String> FlattenGetString(Handle<String> str);
-Handle<Object> SetProperty(Isolate* isolate,
- Handle<Object> object,
- Handle<Object> key,
- Handle<Object> value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode);
-
Handle<Object> ForceSetProperty(Handle<JSObject> object,
Handle<Object> key,
Handle<Object> value,
diff --git a/src/heap.cc b/src/heap.cc
index 9e877ab..217b37b 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -480,6 +480,20 @@
}
+void Heap::ClearAllICsByKind(Code::Kind kind) {
+ HeapObjectIterator it(code_space());
+
+ for (Object* object = it.Next(); object != NULL; object = it.Next()) {
+ Code* code = Code::cast(object);
+ Code::Kind current_kind = code->kind();
+ if (current_kind == Code::FUNCTION ||
+ current_kind == Code::OPTIMIZED_FUNCTION) {
+ code->ClearInlineCaches(kind);
+ }
+ }
+}
+
+
void Heap::RepairFreeListsAfterBoot() {
PagedSpaces spaces(this);
for (PagedSpace* space = spaces.next();
@@ -753,6 +767,7 @@
isolate()->optimizing_compiler_thread()->Flush();
}
flush_monomorphic_ics_ = true;
+ AgeInlineCaches();
return ++contexts_disposed_;
}
@@ -1150,8 +1165,6 @@
isolate_->counters()->objs_since_last_full()->Set(0);
- contexts_disposed_ = 0;
-
flush_monomorphic_ics_ = false;
}
@@ -4098,13 +4111,12 @@
return result;
}
- Object* result;
+ SeqTwoByteString* result;
{ MaybeObject* maybe_result = AllocateRawTwoByteString(1);
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ if (!maybe_result->To<SeqTwoByteString>(&result)) return maybe_result;
}
- String* answer = String::cast(result);
- answer->Set(0, code);
- return answer;
+ result->SeqTwoByteStringSet(0, code);
+ return result;
}
@@ -5728,12 +5740,7 @@
size_factor * IncrementalMarking::kAllocatedThreshold;
if (contexts_disposed_ > 0) {
- if (hint >= kMaxHint) {
- // The embedder is requesting a lot of GC work after context disposal,
- // we age inline caches so that they don't keep objects from
- // the old context alive.
- AgeInlineCaches();
- }
+ contexts_disposed_ = 0;
int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
if (hint >= mark_sweep_time && !FLAG_expose_gc &&
incremental_marking()->IsStopped()) {
@@ -5742,8 +5749,8 @@
"idle notification: contexts disposed");
} else {
AdvanceIdleIncrementalMarking(step_size);
- contexts_disposed_ = 0;
}
+
// After context disposal there is likely a lot of garbage remaining, reset
// the idle notification counters in order to trigger more incremental GCs
// on subsequent idle notifications.
diff --git a/src/heap.h b/src/heap.h
index cb421d4..782a2eb 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -209,8 +209,10 @@
V(Boolean_string, "Boolean") \
V(callee_string, "callee") \
V(constructor_string, "constructor") \
- V(result_string, ".result") \
+ V(dot_result_string, ".result") \
V(dot_for_string, ".for.") \
+ V(dot_iterator_string, ".iterator") \
+ V(dot_generator_object_string, ".generator_object") \
V(eval_string, "eval") \
V(empty_string, "") \
V(function_string, "function") \
@@ -762,6 +764,9 @@
// Clear the Instanceof cache (used when a prototype changes).
inline void ClearInstanceofCache();
+ // Iterates the whole code space to clear all ICs of the given kind.
+ void ClearAllICsByKind(Code::Kind kind);
+
// For use during bootup.
void RepairFreeListsAfterBoot();
diff --git a/src/hydrogen-gvn.cc b/src/hydrogen-gvn.cc
index e3bf316..02b3a0a 100644
--- a/src/hydrogen-gvn.cc
+++ b/src/hydrogen-gvn.cc
@@ -433,7 +433,7 @@
uint32_t set_depends_on = 0;
uint32_t set_changes = 0;
for (int bit = 0; bit < kLastFlag; ++bit) {
- if ((flags.ToIntegral() & (1 << bit)) != 0) {
+ if (flags.Contains(static_cast<GVNFlag>(bit))) {
if (bit % 2 == 0) {
set_changes++;
} else {
@@ -450,7 +450,7 @@
offset += OS::SNPrintF(buffer + offset, "changes all except [");
}
for (int bit = 0; bit < kLastFlag; ++bit) {
- if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_changes) {
+ if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_changes) {
switch (static_cast<GVNFlag>(bit)) {
#define DECLARE_FLAG(type) \
case kChanges##type: \
@@ -479,7 +479,7 @@
offset += OS::SNPrintF(buffer + offset, "depends on all except [");
}
for (int bit = 0; bit < kLastFlag; ++bit) {
- if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_depends_on) {
+ if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_depends_on) {
switch (static_cast<GVNFlag>(bit)) {
#define DECLARE_FLAG(type) \
case kDependsOn##type: \
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 206ab7e..02abf0b 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -3991,6 +3991,26 @@
}
+HInstruction* HSeqStringGetChar::New(Zone* zone,
+ HValue* context,
+ String::Encoding encoding,
+ HValue* string,
+ HValue* index) {
+ if (FLAG_fold_constants && string->IsConstant() && index->IsConstant()) {
+ HConstant* c_string = HConstant::cast(string);
+ HConstant* c_index = HConstant::cast(index);
+ if (c_string->HasStringValue() && c_index->HasInteger32Value()) {
+ Handle<String> s = c_string->StringValue();
+ int32_t i = c_index->Integer32Value();
+ ASSERT_LE(0, i);
+ ASSERT_LT(i, s->length());
+ return H_CONSTANT_INT(s->Get(i));
+ }
+ }
+ return new(zone) HSeqStringGetChar(encoding, string, index);
+}
+
+
#undef H_CONSTANT_INT
#undef H_CONSTANT_DOUBLE
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 80773bf..02af875 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -159,6 +159,7 @@
V(Return) \
V(Ror) \
V(Sar) \
+ V(SeqStringGetChar) \
V(SeqStringSetChar) \
V(Shl) \
V(Shr) \
@@ -208,7 +209,8 @@
V(GlobalVars) \
V(InobjectFields) \
V(OsrEntries) \
- V(ExternalMemory)
+ V(ExternalMemory) \
+ V(StringChars)
#define DECLARE_ABSTRACT_INSTRUCTION(type) \
@@ -542,7 +544,7 @@
};
-typedef EnumSet<GVNFlag> GVNFlagSet;
+typedef EnumSet<GVNFlag, int64_t> GVNFlagSet;
class HValue : public ZoneObject {
@@ -3257,9 +3259,6 @@
// List of values tracked by this marker.
ZoneList<HValue*> values_;
-
- private:
- virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return true; }
};
@@ -3287,6 +3286,8 @@
set_representation(Representation::Tagged());
SetFlag(kIsArguments);
}
+
+ virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return true; }
};
@@ -3323,6 +3324,11 @@
private:
int capture_id_;
+
+ // Note that we cannot DCE captured objects as they are used to replay
+ // the environment. This method is here as an explicit reminder.
+ // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
+ virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return false; }
};
@@ -6750,6 +6756,7 @@
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
+ SetGVNFlag(kDependsOnStringChars);
SetGVNFlag(kChangesNewSpacePromotion);
}
@@ -7021,6 +7028,56 @@
};
+class HSeqStringGetChar V8_FINAL : public HTemplateInstruction<2> {
+ public:
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ String::Encoding encoding,
+ HValue* string,
+ HValue* index);
+
+ virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
+ return (index == 0) ? Representation::Tagged()
+ : Representation::Integer32();
+ }
+
+ String::Encoding encoding() const { return encoding_; }
+ HValue* string() const { return OperandAt(0); }
+ HValue* index() const { return OperandAt(1); }
+
+ DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
+
+ protected:
+ virtual bool DataEquals(HValue* other) V8_OVERRIDE {
+ return encoding() == HSeqStringGetChar::cast(other)->encoding();
+ }
+
+ virtual Range* InferRange(Zone* zone) V8_OVERRIDE {
+ if (encoding() == String::ONE_BYTE_ENCODING) {
+ return new(zone) Range(0, String::kMaxOneByteCharCode);
+ } else {
+ ASSERT_EQ(String::TWO_BYTE_ENCODING, encoding());
+ return new(zone) Range(0, String::kMaxUtf16CodeUnit);
+ }
+ }
+
+ private:
+ HSeqStringGetChar(String::Encoding encoding,
+ HValue* string,
+ HValue* index) : encoding_(encoding) {
+ SetOperandAt(0, string);
+ SetOperandAt(1, index);
+ set_representation(Representation::Integer32());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnStringChars);
+ }
+
+ virtual bool IsDeletable() const V8_OVERRIDE { return true; }
+
+ String::Encoding encoding_;
+};
+
+
class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<3> {
public:
DECLARE_INSTRUCTION_FACTORY_P4(HSeqStringSetChar, String::Encoding,
@@ -7047,6 +7104,7 @@
SetOperandAt(1, index);
SetOperandAt(2, value);
set_representation(Representation::Tagged());
+ SetGVNFlag(kChangesStringChars);
}
String::Encoding encoding_;
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 2e05654..3075952 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -4310,6 +4310,7 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ expr->BuildConstantProperties(isolate());
Handle<JSFunction> closure = function_state()->compilation_info()->closure();
HInstruction* literal;
@@ -4431,6 +4432,7 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ expr->BuildConstantElements(isolate());
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
HInstruction* literal;
@@ -5576,6 +5578,21 @@
checked_object->ClearGVNFlag(kDependsOnElementsKind);
}
+ if (is_store && map->prototype()->IsJSObject()) {
+ // monomorphic stores need a prototype chain check because shape
+ // changes could allow callbacks on elements in the chain that
+ // aren't compatible with monomorphic keyed stores.
+ Handle<JSObject> prototype(JSObject::cast(map->prototype()));
+ Object* holder = map->prototype();
+ while (holder->GetPrototype(isolate())->IsJSObject()) {
+ holder = holder->GetPrototype(isolate());
+ }
+ ASSERT(holder->GetPrototype(isolate())->IsNull());
+
+ BuildCheckPrototypeMaps(prototype,
+ Handle<JSObject>(JSObject::cast(holder)));
+ }
+
LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
return BuildUncheckedMonomorphicElementAccess(
checked_object, key, val,
@@ -5789,6 +5806,22 @@
SmallMapList* types;
bool monomorphic = ComputeReceiverTypes(expr, obj, &types);
+ bool force_generic = false;
+ if (is_store && (monomorphic || (types != NULL && !types->is_empty()))) {
+ // Stores can't be mono/polymorphic if their prototype chain has dictionary
+ // elements. However a receiver map that has dictionary elements itself
+ // should be left to normal mono/poly behavior (the other maps may benefit
+ // from highly optimized stores).
+ for (int i = 0; i < types->length(); i++) {
+ Handle<Map> current_map = types->at(i);
+ if (current_map->DictionaryElementsInPrototypeChainOnly()) {
+ force_generic = true;
+ monomorphic = false;
+ break;
+ }
+ }
+ }
+
if (monomorphic) {
Handle<Map> map = types->first();
if (map->has_slow_elements_kind()) {
@@ -5800,7 +5833,7 @@
instr = BuildMonomorphicElementAccess(
obj, key, val, NULL, map, is_store, expr->GetStoreMode());
}
- } else if (types != NULL && !types->is_empty()) {
+ } else if (!force_generic && (types != NULL && !types->is_empty())) {
return HandlePolymorphicElementAccess(
obj, key, val, types, is_store,
expr->GetStoreMode(), has_side_effects);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index 40345d8..24c6b92 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -553,6 +553,16 @@
}
+void Assembler::mov_w(const Operand& dst, int16_t imm16) {
+ EnsureSpace ensure_space(this);
+ EMIT(0x66);
+ EMIT(0xC7);
+ emit_operand(eax, dst);
+ EMIT(static_cast<int8_t>(imm16 & 0xff));
+ EMIT(static_cast<int8_t>(imm16 >> 8));
+}
+
+
void Assembler::mov(Register dst, int32_t imm32) {
EnsureSpace ensure_space(this);
EMIT(0xB8 | dst.code());
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 57f496f..a82b517 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -735,6 +735,7 @@
void mov_w(Register dst, const Operand& src);
void mov_w(const Operand& dst, Register src);
+ void mov_w(const Operand& dst, int16_t imm16);
void mov(Register dst, int32_t imm32);
void mov(Register dst, const Immediate& x);
diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
index 4e4d552..d7b28d5 100644
--- a/src/ia32/disasm-ia32.cc
+++ b/src/ia32/disasm-ia32.cc
@@ -1205,6 +1205,13 @@
AppendToBuffer("mov_w ");
data += PrintRightOperand(data);
AppendToBuffer(",%s", NameOfCPURegister(regop));
+ } else if (*data == 0xC7) {
+ data++;
+ AppendToBuffer("%s ", "mov_w");
+ data += PrintRightOperand(data);
+ int imm = *reinterpret_cast<int16_t*>(data);
+ AppendToBuffer(",0x%x", imm);
+ data += 2;
} else if (*data == 0x0F) {
data++;
if (*data == 0x38) {
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 09f5de1..b7ddeac 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -1574,6 +1574,9 @@
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
+
+ int depth = 1;
+ expr->BuildConstantProperties(isolate(), &depth);
Handle<FixedArray> constant_properties = expr->constant_properties();
int flags = expr->fast_elements()
? ObjectLiteral::kFastElements
@@ -1583,7 +1586,7 @@
: ObjectLiteral::kNoFlags;
int properties_count = constant_properties->length() / 2;
if ((FLAG_track_double_fields && expr->may_store_doubles()) ||
- expr->depth() > 1 || Serializer::enabled() ||
+ depth > 1 || Serializer::enabled() ||
flags != ObjectLiteral::kFastElements ||
properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
@@ -1702,6 +1705,8 @@
void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral");
+ int depth = 1;
+ expr->BuildConstantElements(isolate(), &depth);
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements();
@@ -1728,8 +1733,7 @@
DONT_TRACK_ALLOCATION_SITE,
length);
__ CallStub(&stub);
- } else if (expr->depth() > 1 ||
- Serializer::enabled() ||
+ } else if (depth > 1 || Serializer::enabled() ||
length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
@@ -4394,14 +4398,50 @@
PrepareForBailoutForId(prop->LoadId(), TOS_REG);
}
- // Call ToNumber only if operand is not a smi.
- Label no_conversion;
+ // Inline smi case if we are in a loop.
+ Label done, stub_call;
+ JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
- __ JumpIfSmi(eax, &no_conversion, Label::kNear);
+ Label slow;
+ patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
+
+ // Save result for postfix expressions.
+ if (expr->is_postfix()) {
+ if (!context()->IsEffect()) {
+ // Save the result on the stack. If we have a named or keyed property
+ // we store the result under the receiver that is currently on top
+ // of the stack.
+ switch (assign_type) {
+ case VARIABLE:
+ __ push(eax);
+ break;
+ case NAMED_PROPERTY:
+ __ mov(Operand(esp, kPointerSize), eax);
+ break;
+ case KEYED_PROPERTY:
+ __ mov(Operand(esp, 2 * kPointerSize), eax);
+ break;
+ }
+ }
+ }
+
+ if (expr->op() == Token::INC) {
+ __ add(eax, Immediate(Smi::FromInt(1)));
+ } else {
+ __ sub(eax, Immediate(Smi::FromInt(1)));
+ }
+ __ j(no_overflow, &done, Label::kNear);
+ // Call stub. Undo operation first.
+ if (expr->op() == Token::INC) {
+ __ sub(eax, Immediate(Smi::FromInt(1)));
+ } else {
+ __ add(eax, Immediate(Smi::FromInt(1)));
+ }
+ __ jmp(&stub_call, Label::kNear);
+ __ bind(&slow);
}
ToNumberStub convert_stub;
__ CallStub(&convert_stub);
- __ bind(&no_conversion);
// Save result for postfix expressions.
if (expr->is_postfix()) {
@@ -4423,34 +4463,11 @@
}
}
- // Inline smi case if we are in a loop.
- Label done, stub_call;
- JumpPatchSite patch_site(masm_);
-
- if (ShouldInlineSmiCase(expr->op())) {
- if (expr->op() == Token::INC) {
- __ add(eax, Immediate(Smi::FromInt(1)));
- } else {
- __ sub(eax, Immediate(Smi::FromInt(1)));
- }
- __ j(overflow, &stub_call, Label::kNear);
- // We could eliminate this smi check if we split the code at
- // the first smi check before calling ToNumber.
- patch_site.EmitJumpIfSmi(eax, &done, Label::kNear);
-
- __ bind(&stub_call);
- // Call stub. Undo operation first.
- if (expr->op() == Token::INC) {
- __ sub(eax, Immediate(Smi::FromInt(1)));
- } else {
- __ add(eax, Immediate(Smi::FromInt(1)));
- }
- }
-
// Record position before stub call.
SetSourcePosition(expr->position());
// Call stub for +1/-1.
+ __ bind(&stub_call);
__ mov(edx, eax);
__ mov(eax, Immediate(Smi::FromInt(1)));
BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index f8e4ea5..0b7c4a8 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -733,6 +733,19 @@
__ cmp(edi, masm->isolate()->factory()->fixed_array_map());
__ j(not_equal, fast_double);
}
+
+ // HOLECHECK: guards "A[i] = V"
+ // We have to go to the runtime if the current value is the hole because
+ // there may be a callback on the element
+ Label holecheck_passed1;
+ __ cmp(CodeGenerator::FixedArrayElementOperand(ebx, ecx),
+ masm->isolate()->factory()->the_hole_value());
+ __ j(not_equal, &holecheck_passed1);
+ __ JumpIfDictionaryInPrototypeChain(edx, ebx, edi, slow);
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+
+ __ bind(&holecheck_passed1);
+
// Smi stores don't require further checks.
Label non_smi_value;
__ JumpIfNotSmi(eax, &non_smi_value);
@@ -773,6 +786,16 @@
// If the value is a number, store it as a double in the FastDoubleElements
// array.
}
+
+ // HOLECHECK: guards "A[i] double hole?"
+ // We have to see if the double version of the hole is present. If so
+ // go to the runtime.
+ uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
+ __ cmp(FieldOperand(ebx, ecx, times_4, offset), Immediate(kHoleNanUpper32));
+ __ j(not_equal, &fast_double_without_map_check);
+ __ JumpIfDictionaryInPrototypeChain(edx, ebx, edi, slow);
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+
__ bind(&fast_double_without_map_check);
__ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
&transition_double_elements, false);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index a69ef12..44b952c 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2059,32 +2059,90 @@
}
-void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+Operand LCodeGen::BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding) {
+ if (index->IsConstantOperand()) {
+ int offset = ToRepresentation(LConstantOperand::cast(index),
+ Representation::Integer32());
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ offset *= kUC16Size;
+ }
+ STATIC_ASSERT(kCharSize == 1);
+ return FieldOperand(string, SeqString::kHeaderSize + offset);
+ }
+ return FieldOperand(
+ string, ToRegister(index),
+ encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
+ SeqString::kHeaderSize);
+}
+
+
+void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
+ Register result = ToRegister(instr->result());
Register string = ToRegister(instr->string());
- Register index = ToRegister(instr->index());
- Register value = ToRegister(instr->value());
- String::Encoding encoding = instr->encoding();
if (FLAG_debug_code) {
- __ push(value);
- __ mov(value, FieldOperand(string, HeapObject::kMapOffset));
- __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
+ __ push(string);
+ __ mov(string, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset));
- __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- __ cmp(value, Immediate(encoding == String::ONE_BYTE_ENCODING
- ? one_byte_seq_type : two_byte_seq_type));
+ __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
__ Check(equal, kUnexpectedStringType);
- __ pop(value);
+ __ pop(string);
}
+ Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
if (encoding == String::ONE_BYTE_ENCODING) {
- __ mov_b(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
- value);
+ __ movzx_b(result, operand);
} else {
- __ mov_w(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
- value);
+ __ movzx_w(result, operand);
+ }
+}
+
+
+void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
+ Register string = ToRegister(instr->string());
+
+ if (FLAG_debug_code) {
+ __ push(string);
+ __ mov(string, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset));
+
+ __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
+ __ Check(equal, kUnexpectedStringType);
+ __ pop(string);
+ }
+
+ Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (instr->value()->IsConstantOperand()) {
+ int value = ToRepresentation(LConstantOperand::cast(instr->value()),
+ Representation::Integer32());
+ ASSERT_LE(0, value);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ ASSERT_LE(value, String::kMaxOneByteCharCode);
+ __ mov_b(operand, static_cast<int8_t>(value));
+ } else {
+ ASSERT_LE(value, String::kMaxUtf16CodeUnit);
+ __ mov_w(operand, static_cast<int16_t>(value));
+ }
+ } else {
+ Register value = ToRegister(instr->value());
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ mov_b(operand, value);
+ } else {
+ __ mov_w(operand, value);
+ }
}
}
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 78bc69d..77a37a6 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -295,6 +295,10 @@
uint32_t offset,
uint32_t additional_index = 0);
+ Operand BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding);
+
void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index fdddef3..80dbdd5 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -580,6 +580,14 @@
}
+LOperand* LChunkBuilder::UseFixedOrConstant(HValue* value,
+ Register fixed_register) {
+ return CanBeImmediateConstant(value)
+ ? chunk_->DefineConstantOperand(HConstant::cast(value))
+ : UseFixed(value, fixed_register);
+}
+
+
LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
return CanBeImmediateConstant(value)
? chunk_->DefineConstantOperand(HConstant::cast(value))
@@ -1865,14 +1873,20 @@
}
+LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
+}
+
+
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
- LOperand* string = UseRegister(instr->string());
- LOperand* index = UseRegister(instr->index());
- ASSERT(ecx.is_byte_register());
- LOperand* value = UseFixed(instr->value(), ecx);
- LSeqStringSetChar* result =
- new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
- return DefineSameAsFirst(result);
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ LOperand* value = (instr->encoding() == String::ONE_BYTE_ENCODING)
+ ? UseFixedOrConstant(instr->value(), eax)
+ : UseRegisterOrConstantAtStart(instr->value());
+ return new(zone()) LSeqStringSetChar(string, index, value);
}
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 752fdd4..dc26626 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -156,6 +156,7 @@
V(PushArgument) \
V(RegExpLiteral) \
V(Return) \
+ V(SeqStringGetChar) \
V(SeqStringSetChar) \
V(ShiftI) \
V(SmiTag) \
@@ -1337,27 +1338,37 @@
};
+class LSeqStringGetChar V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+ LSeqStringGetChar(LOperand* string, LOperand* index) {
+ inputs_[0] = string;
+ inputs_[1] = index;
+ }
+
+ LOperand* string() const { return inputs_[0]; }
+ LOperand* index() const { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar, "seq-string-get-char")
+ DECLARE_HYDROGEN_ACCESSOR(SeqStringGetChar)
+};
+
+
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LSeqStringSetChar(String::Encoding encoding,
- LOperand* string,
+ LSeqStringSetChar(LOperand* string,
LOperand* index,
- LOperand* value) : encoding_(encoding) {
+ LOperand* value) {
inputs_[0] = string;
inputs_[1] = index;
inputs_[2] = value;
}
- String::Encoding encoding() { return encoding_; }
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
-
- private:
- String::Encoding encoding_;
};
@@ -2832,6 +2843,10 @@
MUST_USE_RESULT LOperand* UseOrConstant(HValue* value);
MUST_USE_RESULT LOperand* UseOrConstantAtStart(HValue* value);
+ // An input operand in a fixed register or a constant operand.
+ MUST_USE_RESULT LOperand* UseFixedOrConstant(HValue* value,
+ Register fixed_register);
+
// An input operand in a register or a constant operand.
MUST_USE_RESULT LOperand* UseRegisterOrConstant(HValue* value);
MUST_USE_RESULT LOperand* UseRegisterOrConstantAtStart(HValue* value);
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 025bd89..8414f85 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -3551,6 +3551,32 @@
}
+void MacroAssembler::JumpIfDictionaryInPrototypeChain(
+ Register object,
+ Register scratch0,
+ Register scratch1,
+ Label* found) {
+ ASSERT(!scratch1.is(scratch0));
+ Factory* factory = isolate()->factory();
+ Register current = scratch0;
+ Label loop_again;
+
+ // scratch contained elements pointer.
+ mov(current, object);
+
+ // Loop based on the map going up the prototype chain.
+ bind(&loop_again);
+ mov(current, FieldOperand(current, HeapObject::kMapOffset));
+ mov(scratch1, FieldOperand(current, Map::kBitField2Offset));
+ and_(scratch1, Map::kElementsKindMask);
+ shr(scratch1, Map::kElementsKindShift);
+ cmp(scratch1, Immediate(DICTIONARY_ELEMENTS));
+ j(equal, found);
+ mov(current, FieldOperand(current, Map::kPrototypeOffset));
+ cmp(current, Immediate(factory->null_value()));
+ j(not_equal, &loop_again);
+}
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 30f8a8d..023a08b 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -975,6 +975,10 @@
bind(&no_memento_found);
}
+ // Jumps to found label if a prototype map has dictionary elements.
+ void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
+ Register scratch1, Label* found);
+
private:
bool generating_stub_;
bool allow_stub_calls_;
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 0648833..23e2398 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -3125,9 +3125,7 @@
bool is_dont_delete) {
Label success, miss;
- __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
- HandlerFrontendHeader(
- object, receiver(), Handle<JSObject>::cast(global), name, &miss);
+ HandlerFrontendHeader(object, receiver(), global, name, &miss);
// Get the value from the cell.
if (Serializer::enabled()) {
__ mov(eax, Immediate(cell));
@@ -3154,7 +3152,7 @@
__ ret(0);
// Return the generated code.
- return GetICCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), Code::NORMAL, name);
}
diff --git a/src/ic.cc b/src/ic.cc
index 55d7ba9..640b188 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -270,8 +270,6 @@
bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
Handle<String> name) {
- DisallowHeapAllocation no_gc;
-
if (target()->is_call_stub()) {
LookupResult lookup(isolate());
LookupForRead(receiver, name, &lookup);
@@ -768,12 +766,13 @@
// Bail out if we didn't find a result.
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
- // Compute the number of arguments.
- Handle<Code> code;
- code = state() == UNINITIALIZED
- ? pre_monomorphic_stub()
- : ComputeMonomorphicStub(lookup, object, name);
+ if (state() == UNINITIALIZED) {
+ set_target(*pre_monomorphic_stub());
+ TRACE_IC("CallIC", name);
+ return;
+ }
+ Handle<Code> code = ComputeMonomorphicStub(lookup, object, name);
// If there's no appropriate stub we simply avoid updating the caches.
// TODO(verwaest): Install a slow fallback in this case to avoid not learning,
// and deopting Crankshaft code.
@@ -954,39 +953,36 @@
Handle<String> name,
Handle<Code> code) {
if (!code->is_handler()) return false;
-
MapHandleList receiver_maps;
CodeHandleList handlers;
int number_of_valid_maps;
int handler_to_overwrite = -1;
Handle<Map> new_receiver_map(receiver->map());
- {
- DisallowHeapAllocation no_gc;
- target()->FindAllMaps(&receiver_maps);
- int number_of_maps = receiver_maps.length();
- number_of_valid_maps = number_of_maps;
- for (int i = 0; i < number_of_maps; i++) {
- Handle<Map> map = receiver_maps.at(i);
- // Filter out deprecated maps to ensure its instances get migrated.
- if (map->is_deprecated()) {
- number_of_valid_maps--;
- // If the receiver map is already in the polymorphic IC, this indicates
- // there was a prototoype chain failure. In that case, just overwrite the
- // handler.
- } else if (map.is_identical_to(new_receiver_map)) {
- number_of_valid_maps--;
- handler_to_overwrite = i;
- }
+ target()->FindAllMaps(&receiver_maps);
+ int number_of_maps = receiver_maps.length();
+ number_of_valid_maps = number_of_maps;
+
+ for (int i = 0; i < number_of_maps; i++) {
+ Handle<Map> map = receiver_maps.at(i);
+ // Filter out deprecated maps to ensure its instances get migrated.
+ if (map->is_deprecated()) {
+ number_of_valid_maps--;
+ // If the receiver map is already in the polymorphic IC, this indicates
+ // there was a prototoype chain failure. In that case, just overwrite the
+ // handler.
+ } else if (map.is_identical_to(new_receiver_map)) {
+ number_of_valid_maps--;
+ handler_to_overwrite = i;
}
+ }
- if (number_of_valid_maps >= 4) return false;
- if (number_of_maps == 0) return false;
+ if (number_of_valid_maps >= 4) return false;
+ if (number_of_maps == 0) return false;
- if (!target()->FindHandlers(&handlers, receiver_maps.length())) {
- return false;
- }
+ if (!target()->FindHandlers(&handlers, receiver_maps.length())) {
+ return false;
}
number_of_valid_maps++;
@@ -1017,11 +1013,8 @@
void IC::CopyICToMegamorphicCache(Handle<String> name) {
MapHandleList receiver_maps;
CodeHandleList handlers;
- {
- DisallowHeapAllocation no_gc;
- target()->FindAllMaps(&receiver_maps);
- if (!target()->FindHandlers(&handlers, receiver_maps.length())) return;
- }
+ target()->FindAllMaps(&receiver_maps);
+ if (!target()->FindHandlers(&handlers, receiver_maps.length())) return;
for (int i = 0; i < receiver_maps.length(); i++) {
UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
}
@@ -1029,8 +1022,6 @@
bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
- DisallowHeapAllocation no_allocation;
-
Map* current_map = target()->FindFirstMap();
ElementsKind receiver_elements_kind = receiver_map->elements_kind();
bool more_general_transition =
@@ -1061,43 +1052,26 @@
!target().is_identical_to(code));
if (!target()->is_keyed_stub()) {
bool is_same_handler = false;
- {
- DisallowHeapAllocation no_allocation;
- Code* old_handler = target()->FindFirstHandler();
- is_same_handler = old_handler == *code;
- }
- if (is_same_handler
- && IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
+ Code* old_handler = target()->FindFirstHandler();
+ is_same_handler = old_handler == *code;
+
+ if (is_same_handler &&
+ IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
UpdateMonomorphicIC(receiver, code, name);
break;
}
- if (UpdatePolymorphicIC(receiver, name, code)) {
- break;
- }
-
+ }
+ // Fall through.
+ case POLYMORPHIC:
+ if (!target()->is_keyed_stub()) {
+ if (UpdatePolymorphicIC(receiver, name, code)) break;
CopyICToMegamorphicCache(name);
}
-
- UpdateMegamorphicCache(receiver->map(), *name, *code);
set_target(*megamorphic_stub());
- break;
+ // Fall through.
case MEGAMORPHIC:
UpdateMegamorphicCache(receiver->map(), *name, *code);
break;
- case POLYMORPHIC:
- if (target()->is_keyed_stub()) {
- // When trying to patch a polymorphic keyed stub with anything other
- // than another polymorphic stub, go generic.
- set_target(*generic_stub());
- } else {
- if (UpdatePolymorphicIC(receiver, name, code)) {
- break;
- }
- CopyICToMegamorphicCache(name);
- UpdateMegamorphicCache(receiver->map(), *name, *code);
- set_target(*megamorphic_stub());
- }
- break;
case DEBUG_STUB:
break;
case GENERIC:
@@ -1119,6 +1093,7 @@
}
}
+
void LoadIC::UpdateCaches(LookupResult* lookup,
Handle<Object> object,
Handle<String> name) {
@@ -1133,7 +1108,9 @@
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
- code = pre_monomorphic_stub();
+ set_target(*pre_monomorphic_stub());
+ TRACE_IC("LoadIC", name);
+ return;
} else if (!lookup->IsCacheable()) {
// Bail out if the result is not cacheable.
code = slow_stub();
@@ -1175,8 +1152,9 @@
if (!code.is_null()) return code;
code = CompileHandler(lookup, receiver, name, value);
+ ASSERT(code->is_handler());
- if (code->is_handler() && code->type() != Code::NORMAL) {
+ if (code->type() != Code::NORMAL) {
HeapObject::UpdateMapCodeCache(receiver, name, code);
}
@@ -1215,9 +1193,11 @@
Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
- // TODO(verwaest): Turn into a handler.
- return isolate()->stub_cache()->ComputeLoadGlobal(
- name, receiver, global, cell, lookup->IsDontDelete());
+ Handle<Code> code = compiler.CompileLoadGlobal(
+ receiver, global, cell, name, lookup->IsDontDelete());
+ // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
+ HeapObject::UpdateMapCodeCache(receiver, name, code);
+ return code;
}
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
@@ -1632,11 +1612,15 @@
// from the property cell. So the property must be directly on the
// global object.
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
- Handle<PropertyCell> cell(
- global->GetPropertyCell(lookup), isolate());
- // TODO(verwaest): Turn into a handler.
- return isolate()->stub_cache()->ComputeStoreGlobal(
- name, global, cell, value, strict_mode());
+ Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate());
+ Handle<Type> union_type = PropertyCell::UpdatedType(cell, value);
+ StoreGlobalStub stub(strict_mode(), union_type->IsConstant());
+
+ Handle<Code> code = stub.GetCodeCopyFromTemplate(
+ isolate(), receiver->map(), *cell);
+ // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
+ HeapObject::UpdateMapCodeCache(receiver, name, code);
+ return code;
}
ASSERT(holder.is_identical_to(receiver));
return strict_mode() == kStrictMode
@@ -1936,8 +1920,13 @@
Handle<Object> value,
ICMissMode miss_mode) {
if (MigrateDeprecated(object)) {
- return Runtime::SetObjectPropertyOrFail(
- isolate(), object , key, value, NONE, strict_mode());
+ Handle<Object> result = Runtime::SetObjectProperty(isolate(), object,
+ key,
+ value,
+ NONE,
+ strict_mode());
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
+ return *result;
}
// Check for values that can be converted into an internalized string directly
@@ -1976,10 +1965,16 @@
isolate()->heap()->non_strict_arguments_elements_map()) {
stub = non_strict_arguments_stub();
} else if (key_is_smi_like &&
- (!target().is_identical_to(non_strict_arguments_stub()))) {
- KeyedAccessStoreMode store_mode =
- GetStoreMode(receiver, key, value);
- stub = StoreElementStub(receiver, store_mode);
+ !(target().is_identical_to(non_strict_arguments_stub()))) {
+ // We should go generic if receiver isn't a dictionary, but our
+ // prototype chain does have dictionary elements. This ensures that
+ // other non-dictionary receivers in the polymorphic case benefit
+ // from fast path keyed stores.
+ if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
+ KeyedAccessStoreMode store_mode =
+ GetStoreMode(receiver, key, value);
+ stub = StoreElementStub(receiver, store_mode);
+ }
}
}
}
@@ -1996,8 +1991,12 @@
}
if (maybe_object) return maybe_object;
- return Runtime::SetObjectPropertyOrFail(
- isolate(), object , key, value, NONE, strict_mode());
+ Handle<Object> result = Runtime::SetObjectProperty(isolate(), object, key,
+ value,
+ NONE,
+ strict_mode());
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
+ return *result;
}
@@ -2228,12 +2227,12 @@
Handle<Object> key = args.at<Object>(1);
Handle<Object> value = args.at<Object>(2);
StrictModeFlag strict_mode = ic.strict_mode();
- return Runtime::SetObjectProperty(isolate,
- object,
- key,
- value,
- NONE,
- strict_mode);
+ Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
+ value,
+ NONE,
+ strict_mode);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
@@ -2245,12 +2244,12 @@
Handle<Object> key = args.at<Object>(1);
Handle<Object> value = args.at<Object>(2);
StrictModeFlag strict_mode = ic.strict_mode();
- return Runtime::SetObjectProperty(isolate,
- object,
- key,
- value,
- NONE,
- strict_mode);
+ Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
+ value,
+ NONE,
+ strict_mode);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
@@ -2270,15 +2269,20 @@
ASSERT(args.length() == 4);
KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
Handle<Object> value = args.at<Object>(0);
+ Handle<Map> map = args.at<Map>(1);
Handle<Object> key = args.at<Object>(2);
Handle<Object> object = args.at<Object>(3);
StrictModeFlag strict_mode = ic.strict_mode();
- return Runtime::SetObjectProperty(isolate,
- object,
- key,
- value,
- NONE,
- strict_mode);
+ if (object->IsJSObject()) {
+ JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
+ map->elements_kind());
+ }
+ Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
+ value,
+ NONE,
+ strict_mode);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
diff --git a/src/isolate.cc b/src/isolate.cc
index 71cd301..0e764bf 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -2465,6 +2465,12 @@
}
+CodeTracer* Isolate::GetCodeTracer() {
+ if (code_tracer() == NULL) set_code_tracer(new CodeTracer(id()));
+ return code_tracer();
+}
+
+
Map* Isolate::get_initial_js_array_map(ElementsKind kind) {
Context* native_context = context()->native_context();
Object* maybe_map_array = native_context->js_array_maps();
diff --git a/src/isolate.h b/src/isolate.h
index 9aa14ee..c13714f 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -55,6 +55,7 @@
class CodeGenerator;
class CodeRange;
struct CodeStubInterfaceDescriptor;
+class CodeTracer;
class CompilationCache;
class ContextSlotCache;
class ContextSwitcher;
@@ -305,7 +306,7 @@
enum ParallelSystemComponent {
PARALLEL_SWEEPING,
CONCURRENT_SWEEPING,
- PARALLEL_RECOMPILATION
+ CONCURRENT_RECOMPILATION
};
static int NumberOfParallelSystemThreads(ParallelSystemComponent type);
@@ -377,6 +378,7 @@
V(bool, observer_delivery_pending, false) \
V(HStatistics*, hstatistics, NULL) \
V(HTracer*, htracer, NULL) \
+ V(CodeTracer*, code_tracer, NULL) \
ISOLATE_DEBUGGER_INIT_LIST(V)
class Isolate {
@@ -1126,6 +1128,7 @@
HStatistics* GetHStatistics();
HTracer* GetHTracer();
+ CodeTracer* GetCodeTracer();
FunctionEntryHook function_entry_hook() { return function_entry_hook_; }
void set_function_entry_hook(FunctionEntryHook function_entry_hook) {
@@ -1507,6 +1510,73 @@
native_context()->set_out_of_memory(GetIsolate()->heap()->true_value());
}
+class CodeTracer V8_FINAL : public Malloced {
+ public:
+ explicit CodeTracer(int isolate_id)
+ : file_(NULL),
+ scope_depth_(0) {
+ if (!ShouldRedirect()) {
+ file_ = stdout;
+ return;
+ }
+
+ if (FLAG_redirect_code_traces_to == NULL) {
+ OS::SNPrintF(filename_,
+ "code-%d-%d.asm",
+ OS::GetCurrentProcessId(),
+ isolate_id);
+ } else {
+ OS::StrNCpy(filename_, FLAG_redirect_code_traces_to, filename_.length());
+ }
+
+ WriteChars(filename_.start(), "", 0, false);
+ }
+
+ class Scope {
+ public:
+ explicit Scope(CodeTracer* tracer) : tracer_(tracer) { tracer->OpenFile(); }
+ ~Scope() { tracer_->CloseFile(); }
+
+ FILE* file() const { return tracer_->file(); }
+
+ private:
+ CodeTracer* tracer_;
+ };
+
+ void OpenFile() {
+ if (!ShouldRedirect()) {
+ return;
+ }
+
+ if (file_ == NULL) {
+ file_ = OS::FOpen(filename_.start(), "a");
+ }
+
+ scope_depth_++;
+ }
+
+ void CloseFile() {
+ if (!ShouldRedirect()) {
+ return;
+ }
+
+ if (--scope_depth_ == 0) {
+ fclose(file_);
+ file_ = NULL;
+ }
+ }
+
+ FILE* file() const { return file_; }
+
+ private:
+ static bool ShouldRedirect() {
+ return FLAG_redirect_code_traces;
+ }
+
+ EmbeddedVector<char, 128> filename_;
+ FILE* file_;
+ int scope_depth_;
+};
} } // namespace v8::internal
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 3a3d915..1f3f2a1 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -1150,7 +1150,9 @@
work_list_ = NULL;
#ifdef DEBUG
if (FLAG_print_code) {
- Handle<Code>::cast(code)->Disassemble(*pattern->ToCString());
+ CodeTracer::Scope trace_scope(heap->isolate()->GetCodeTracer());
+ Handle<Code>::cast(code)->Disassemble(*pattern->ToCString(),
+ trace_scope.file());
}
if (FLAG_trace_regexp_assembler) {
delete macro_assembler_;
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index b217e06..caa7352 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -1644,6 +1644,9 @@
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
+
+ int depth = 1;
+ expr->BuildConstantProperties(isolate(), &depth);
Handle<FixedArray> constant_properties = expr->constant_properties();
__ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
@@ -1658,7 +1661,7 @@
__ li(a0, Operand(Smi::FromInt(flags)));
int properties_count = constant_properties->length() / 2;
if ((FLAG_track_double_fields && expr->may_store_doubles()) ||
- expr->depth() > 1 || Serializer::enabled() ||
+ depth > 1 || Serializer::enabled() ||
flags != ObjectLiteral::kFastElements ||
properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
__ Push(a3, a2, a1, a0);
@@ -1777,6 +1780,8 @@
void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral");
+ int depth = 1;
+ expr->BuildConstantElements(isolate(), &depth);
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
@@ -1803,8 +1808,7 @@
__ CallStub(&stub);
__ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(),
1, a1, a2);
- } else if (expr->depth() > 1 ||
- Serializer::enabled() ||
+ } else if (depth > 1 || Serializer::enabled() ||
length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ Push(a3, a2, a1);
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
@@ -4438,15 +4442,48 @@
PrepareForBailoutForId(prop->LoadId(), TOS_REG);
}
- // Call ToNumber only if operand is not a smi.
- Label no_conversion;
- if (ShouldInlineSmiCase(expr->op())) {
- __ JumpIfSmi(v0, &no_conversion);
- }
+ // Inline smi case if we are in a loop.
+ Label stub_call, done;
+ JumpPatchSite patch_site(masm_);
+
+ int count_value = expr->op() == Token::INC ? 1 : -1;
__ mov(a0, v0);
+ if (ShouldInlineSmiCase(expr->op())) {
+ Label slow;
+ patch_site.EmitJumpIfNotSmi(v0, &slow);
+
+ // Save result for postfix expressions.
+ if (expr->is_postfix()) {
+ if (!context()->IsEffect()) {
+ // Save the result on the stack. If we have a named or keyed property
+ // we store the result under the receiver that is currently on top
+ // of the stack.
+ switch (assign_type) {
+ case VARIABLE:
+ __ push(v0);
+ break;
+ case NAMED_PROPERTY:
+ __ sw(v0, MemOperand(sp, kPointerSize));
+ break;
+ case KEYED_PROPERTY:
+ __ sw(v0, MemOperand(sp, 2 * kPointerSize));
+ break;
+ }
+ }
+ }
+
+ Register scratch1 = a1;
+ Register scratch2 = t0;
+ __ li(scratch1, Operand(Smi::FromInt(count_value)));
+ __ AdduAndCheckForOverflow(v0, v0, scratch1, scratch2);
+ __ BranchOnNoOverflow(&done, scratch2);
+ // Call stub. Undo operation first.
+ __ Move(v0, a0);
+ __ jmp(&stub_call);
+ __ bind(&slow);
+ }
ToNumberStub convert_stub;
__ CallStub(&convert_stub);
- __ bind(&no_conversion);
// Save result for postfix expressions.
if (expr->is_postfix()) {
@@ -4467,24 +4504,9 @@
}
}
}
- __ mov(a0, result_register());
- // Inline smi case if we are in a loop.
- Label stub_call, done;
- JumpPatchSite patch_site(masm_);
-
- int count_value = expr->op() == Token::INC ? 1 : -1;
- if (ShouldInlineSmiCase(expr->op())) {
- __ li(a1, Operand(Smi::FromInt(count_value)));
- __ AdduAndCheckForOverflow(v0, a0, a1, t0);
- __ BranchOnOverflow(&stub_call, t0); // Do stub on overflow.
-
- // We could eliminate this smi check if we split the code at
- // the first smi check before calling ToNumber.
- patch_site.EmitJumpIfSmi(v0, &done);
- __ bind(&stub_call);
- }
- __ mov(a1, a0);
+ __ bind(&stub_call);
+ __ mov(a1, v0);
__ li(a0, Operand(Smi::FromInt(count_value)));
// Record position before stub call.
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index 9813da4..0fe044a 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -1180,6 +1180,22 @@
__ Branch(fast_double, ne, elements_map,
Operand(masm->isolate()->factory()->fixed_array_map()));
}
+
+ // HOLECHECK: guards "A[i] = V"
+ // We have to go to the runtime if the current value is the hole because
+ // there may be a callback on the element.
+ Label holecheck_passed1;
+ __ Addu(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
+ __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
+ __ addu(address, address, at);
+ __ lw(scratch_value, MemOperand(address));
+ __ Branch(&holecheck_passed1, ne, scratch_value,
+ Operand(masm->isolate()->factory()->the_hole_value()));
+ __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
+ slow);
+
+ __ bind(&holecheck_passed1);
+
// Smi stores don't require further checks.
Label non_smi_value;
__ JumpIfNotSmi(value, &non_smi_value);
@@ -1230,6 +1246,21 @@
__ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
__ Branch(slow, ne, elements_map, Operand(at));
}
+
+ // HOLECHECK: guards "A[i] double hole?"
+ // We have to see if the double version of the hole is present. If so
+ // go to the runtime.
+ __ Addu(address, elements,
+ Operand(FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32)
+ - kHeapObjectTag));
+ __ sll(at, key, kPointerSizeLog2);
+ __ addu(address, address, at);
+ __ lw(scratch_value, MemOperand(address));
+ __ Branch(&fast_double_without_map_check, ne, scratch_value,
+ Operand(kHoleNanUpper32));
+ __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
+ slow);
+
__ bind(&fast_double_without_map_check);
__ StoreNumberToDoubleElements(value,
key,
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 8fa397b..34c3155 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -738,13 +738,23 @@
return;
}
- ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS.
- if (FLAG_deopt_every_n_times == 1 &&
- !info()->IsStub() &&
- info()->opt_count() == id) {
- ASSERT(frame_is_built_);
+ if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
+ Register scratch = scratch0();
+ ExternalReference count = ExternalReference::stress_deopt_count(isolate());
+ Label no_deopt;
+ __ Push(a1, scratch);
+ __ li(scratch, Operand(count));
+ __ lw(a1, MemOperand(scratch));
+ __ Subu(a1, a1, Operand(1));
+ __ Branch(&no_deopt, ne, a1, Operand(zero_reg));
+ __ li(a1, Operand(FLAG_deopt_every_n_times));
+ __ sw(a1, MemOperand(scratch));
+ __ Pop(a1, scratch);
+
__ Call(entry, RelocInfo::RUNTIME_ENTRY);
- return;
+ __ bind(&no_deopt);
+ __ sw(a1, MemOperand(scratch));
+ __ Pop(a1, scratch);
}
if (info()->ShouldTrapOnDeopt()) {
@@ -1731,14 +1741,38 @@
}
-void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
- Register string = ToRegister(instr->string());
- LOperand* index_op = instr->index();
- Register value = ToRegister(instr->value());
+MemOperand LCodeGen::BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding) {
+ if (index->IsConstantOperand()) {
+ int offset = ToInteger32(LConstantOperand::cast(index));
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ offset *= kUC16Size;
+ }
+ STATIC_ASSERT(kCharSize == 1);
+ return FieldMemOperand(string, SeqString::kHeaderSize + offset);
+ }
Register scratch = scratch0();
- String::Encoding encoding = instr->encoding();
+ ASSERT(!scratch.is(string));
+ ASSERT(!scratch.is(ToRegister(index)));
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ Addu(scratch, string, ToRegister(index));
+ } else {
+ STATIC_ASSERT(kUC16Size == 2);
+ __ sll(scratch, ToRegister(index), 1);
+ __ Addu(scratch, string, scratch);
+ }
+ return FieldMemOperand(scratch, SeqString::kHeaderSize);
+}
+
+
+void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
+ Register string = ToRegister(instr->string());
+ Register result = ToRegister(instr->result());
if (FLAG_debug_code) {
+ Register scratch = scratch0();
__ lw(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
__ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
@@ -1751,25 +1785,39 @@
__ Check(eq, kUnexpectedStringType, at, Operand(zero_reg));
}
- if (index_op->IsConstantOperand()) {
- int constant_index = ToInteger32(LConstantOperand::cast(index_op));
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ sb(value,
- FieldMemOperand(string, SeqString::kHeaderSize + constant_index));
- } else {
- __ sh(value,
- FieldMemOperand(string, SeqString::kHeaderSize + constant_index * 2));
- }
+ MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ lbu(result, operand);
} else {
- Register index = ToRegister(index_op);
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ Addu(scratch, string, Operand(index));
- __ sb(value, FieldMemOperand(scratch, SeqString::kHeaderSize));
- } else {
- __ sll(scratch, index, 1);
- __ Addu(scratch, string, scratch);
- __ sh(value, FieldMemOperand(scratch, SeqString::kHeaderSize));
- }
+ __ lhu(result, operand);
+ }
+}
+
+
+void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
+ Register string = ToRegister(instr->string());
+ Register value = ToRegister(instr->value());
+
+ if (FLAG_debug_code) {
+ Register scratch = scratch0();
+ __ lw(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
+ __ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+
+ __ And(scratch, scratch,
+ Operand(kStringRepresentationMask | kStringEncodingMask));
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ __ Subu(at, scratch, Operand(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
+ __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg));
+ }
+
+ MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ sb(value, operand);
+ } else {
+ __ sh(value, operand);
}
}
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index d0909ae..f41adbf 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -277,6 +277,10 @@
Register ToRegister(int index) const;
DoubleRegister ToDoubleRegister(int index) const;
+ MemOperand BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding);
+
void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index ba7346f..7686096 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -1804,11 +1804,18 @@
}
+LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
+}
+
+
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegisterOrConstant(instr->index());
LOperand* value = UseRegister(instr->value());
- return new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
+ return new(zone()) LSeqStringSetChar(string, index, value);
}
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 7254d83..14bd29b 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -155,6 +155,7 @@
V(Random) \
V(RegExpLiteral) \
V(Return) \
+ V(SeqStringGetChar) \
V(SeqStringSetChar) \
V(ShiftI) \
V(SmiTag) \
@@ -1340,27 +1341,37 @@
};
+class LSeqStringGetChar V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+ LSeqStringGetChar(LOperand* string, LOperand* index) {
+ inputs_[0] = string;
+ inputs_[1] = index;
+ }
+
+ LOperand* string() const { return inputs_[0]; }
+ LOperand* index() const { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar, "seq-string-get-char")
+ DECLARE_HYDROGEN_ACCESSOR(SeqStringGetChar)
+};
+
+
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LSeqStringSetChar(String::Encoding encoding,
- LOperand* string,
+ LSeqStringSetChar(LOperand* string,
LOperand* index,
- LOperand* value) : encoding_(encoding) {
+ LOperand* value) {
inputs_[0] = string;
inputs_[1] = index;
inputs_[2] = value;
}
- String::Encoding encoding() { return encoding_; }
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
-
- private:
- String::Encoding encoding_;
};
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index c434c31..f751e59 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -5654,6 +5654,30 @@
}
+void MacroAssembler::JumpIfDictionaryInPrototypeChain(
+ Register object,
+ Register scratch0,
+ Register scratch1,
+ Label* found) {
+ ASSERT(!scratch1.is(scratch0));
+ Factory* factory = isolate()->factory();
+ Register current = scratch0;
+ Label loop_again;
+
+ // Scratch contained elements pointer.
+ Move(current, object);
+
+ // Loop based on the map going up the prototype chain.
+ bind(&loop_again);
+ lw(current, FieldMemOperand(current, HeapObject::kMapOffset));
+ lb(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
+ Ext(scratch1, scratch1, Map::kElementsKindShift, Map::kElementsKindBitCount);
+ Branch(found, eq, scratch1, Operand(DICTIONARY_ELEMENTS));
+ lw(current, FieldMemOperand(current, Map::kPrototypeOffset));
+ Branch(&loop_again, ne, current, Operand(factory->null_value()));
+}
+
+
bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
if (r1.is(r2)) return true;
if (r1.is(r3)) return true;
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 0d232e4..77f1e9b 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -1526,6 +1526,10 @@
bind(&no_memento_found);
}
+ // Jumps to found label if a prototype map has dictionary elements.
+ void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
+ Register scratch1, Label* found);
+
private:
void CallCFunctionHelper(Register function,
int num_reg_arguments,
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 68e2074..27be2d4 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -3032,10 +3032,7 @@
bool is_dont_delete) {
Label success, miss;
- __ CheckMap(
- receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
- HandlerFrontendHeader(
- object, receiver(), Handle<JSObject>::cast(global), name, &miss);
+ HandlerFrontendHeader(object, receiver(), global, name, &miss);
// Get the value from the cell.
__ li(a3, Operand(cell));
@@ -3056,7 +3053,7 @@
__ mov(v0, t0);
// Return the generated code.
- return GetICCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), Code::NORMAL, name);
}
diff --git a/src/object-observe.js b/src/object-observe.js
index 718920f..73a5d34 100644
--- a/src/object-observe.js
+++ b/src/object-observe.js
@@ -128,11 +128,11 @@
}
var defaultAcceptTypes = TypeMapCreateFromList([
- 'new',
- 'updated',
- 'deleted',
- 'prototype',
- 'reconfigured',
+ 'add',
+ 'update',
+ 'delete',
+ 'setPrototype',
+ 'reconfigure',
'preventExtensions'
]);
@@ -353,9 +353,9 @@
}
function ArrayObserve(object, callback) {
- return ObjectObserve(object, callback, ['new',
- 'updated',
- 'deleted',
+ return ObjectObserve(object, callback, ['add',
+ 'update',
+ 'delete',
'splice']);
}
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 60c1ef4..37ae9b6 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -830,7 +830,7 @@
byte_length()->ShortPrint(out);
PrintF(out, "\n - length = ");
length()->ShortPrint(out);
- PrintF("\n");
+ PrintF(out, "\n");
PrintElements(out);
}
@@ -844,7 +844,7 @@
byte_offset()->ShortPrint(out);
PrintF(out, "\n - byte_length = ");
byte_length()->ShortPrint(out);
- PrintF("\n");
+ PrintF(out, "\n");
}
diff --git a/src/objects.cc b/src/objects.cc
index d5f0443..441c25e 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2157,7 +2157,7 @@
object->map()->is_observed() &&
*name != isolate->heap()->hidden_string()) {
Handle<Object> old_value = isolate->factory()->the_hole_value();
- EnqueueChangeRecord(object, "new", name, old_value);
+ EnqueueChangeRecord(object, "add", name, old_value);
}
return value;
@@ -4105,14 +4105,14 @@
if (is_observed) {
if (lookup->IsTransition()) {
- EnqueueChangeRecord(object, "new", name, old_value);
+ EnqueueChangeRecord(object, "add", name, old_value);
} else {
LookupResult new_lookup(isolate);
object->LocalLookup(*name, &new_lookup, true);
if (new_lookup.IsDataProperty()) {
Handle<Object> new_value = Object::GetProperty(object, name);
if (!new_value->SameValue(*old_value)) {
- EnqueueChangeRecord(object, "updated", name, old_value);
+ EnqueueChangeRecord(object, "update", name, old_value);
}
}
}
@@ -4222,9 +4222,9 @@
if (is_observed) {
if (lookup.IsTransition()) {
- EnqueueChangeRecord(object, "new", name, old_value);
+ EnqueueChangeRecord(object, "add", name, old_value);
} else if (old_value->IsTheHole()) {
- EnqueueChangeRecord(object, "reconfigured", name, old_value);
+ EnqueueChangeRecord(object, "reconfigure", name, old_value);
} else {
LookupResult new_lookup(isolate);
object->LocalLookup(*name, &new_lookup, true);
@@ -4235,9 +4235,9 @@
}
if (new_lookup.GetAttributes() != old_attributes) {
if (!value_changed) old_value = isolate->factory()->the_hole_value();
- EnqueueChangeRecord(object, "reconfigured", name, old_value);
+ EnqueueChangeRecord(object, "reconfigure", name, old_value);
} else if (value_changed) {
- EnqueueChangeRecord(object, "updated", name, old_value);
+ EnqueueChangeRecord(object, "update", name, old_value);
}
}
}
@@ -5183,7 +5183,7 @@
if (should_enqueue_change_record && !HasLocalElement(object, index)) {
Handle<String> name = factory->Uint32ToString(index);
- EnqueueChangeRecord(object, "deleted", name, old_value);
+ EnqueueChangeRecord(object, "delete", name, old_value);
}
return result;
@@ -5259,7 +5259,7 @@
}
if (is_observed && !HasLocalProperty(object, name)) {
- EnqueueChangeRecord(object, "deleted", name, old_value);
+ EnqueueChangeRecord(object, "delete", name, old_value);
}
return result;
@@ -6219,6 +6219,31 @@
}
+bool Map::DictionaryElementsInPrototypeChainOnly() {
+ Heap* heap = GetHeap();
+
+ if (IsDictionaryElementsKind(elements_kind())) {
+ return false;
+ }
+
+ for (Object* prototype = this->prototype();
+ prototype != heap->null_value();
+ prototype = prototype->GetPrototype(GetIsolate())) {
+ if (prototype->IsJSProxy()) {
+ // Be conservative, don't walk into proxies.
+ return true;
+ }
+
+ if (IsDictionaryElementsKind(
+ JSObject::cast(prototype)->map()->elements_kind())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
void JSObject::SetElementCallback(Handle<JSObject> object,
uint32_t index,
Handle<Object> structure,
@@ -6227,6 +6252,7 @@
PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
// Normalize elements to make this operation simple.
+ bool had_dictionary_elements = object->HasDictionaryElements();
Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
ASSERT(object->HasDictionaryElements() ||
object->HasDictionaryArgumentsElements());
@@ -6250,6 +6276,11 @@
parameter_map->set(1, *dictionary);
} else {
object->set_elements(*dictionary);
+
+ if (!had_dictionary_elements) {
+ // KeyedStoreICs (at least the non-generic ones) need a reset.
+ heap->ClearAllICsByKind(Code::KEYED_STORE_IC);
+ }
}
}
@@ -6349,7 +6380,7 @@
}
if (is_observed) {
- const char* type = preexists ? "reconfigured" : "new";
+ const char* type = preexists ? "reconfigure" : "add";
EnqueueChangeRecord(object, type, name, old_value);
}
}
@@ -9557,7 +9588,7 @@
if (value->IsSmi()) {
// No optimized code map.
ASSERT_EQ(0, Smi::cast(value)->value());
- // Crate 3 entries per context {context, code, literals}.
+ // Create 3 entries per context {context, code, literals}.
MaybeObject* maybe = heap->AllocateFixedArray(kInitialLength);
if (!maybe->To(&new_code_map)) return maybe;
new_code_map->set(kEntriesStart + 0, native_context);
@@ -10512,7 +10543,7 @@
void Code::ReplaceNthObject(int n,
Map* match_map,
Object* replace_with) {
- ASSERT(is_inline_cache_stub());
+ ASSERT(is_inline_cache_stub() || is_handler());
DisallowHeapAllocation no_allocation;
int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
for (RelocIterator it(this, mask); !it.done(); it.next()) {
@@ -10609,6 +10640,16 @@
void Code::ClearInlineCaches() {
+ ClearInlineCaches(NULL);
+}
+
+
+void Code::ClearInlineCaches(Code::Kind kind) {
+ ClearInlineCaches(&kind);
+}
+
+
+void Code::ClearInlineCaches(Code::Kind* kind) {
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
@@ -10617,7 +10658,9 @@
RelocInfo* info = it.rinfo();
Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
if (target->is_inline_cache_stub()) {
- IC::Clear(this->GetIsolate(), info->pc());
+ if (kind == NULL || *kind == target->kind()) {
+ IC::Clear(this->GetIsolate(), info->pc());
+ }
}
}
}
@@ -10788,7 +10831,7 @@
}
-void Code::PrintDeoptLocation(int bailout_id) {
+void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
const char* last_comment = NULL;
int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
| RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
@@ -10802,7 +10845,7 @@
(bailout_id == Deoptimizer::GetDeoptimizationId(
GetIsolate(), info->target_address(), Deoptimizer::SOFT))) {
CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
- PrintF(" %s\n", last_comment);
+ PrintF(out, " %s\n", last_comment);
return;
}
}
@@ -11004,10 +11047,10 @@
this->DeoptPoints());
if (this->DeoptPoints() == 0) return;
- PrintF("%6s %8s %s\n", "ast id", "pc", "state");
+ PrintF(out, "%6s %8s %s\n", "ast id", "pc", "state");
for (int i = 0; i < this->DeoptPoints(); i++) {
int pc_and_state = this->PcAndState(i)->value();
- PrintF("%6d %8d %s\n",
+ PrintF(out, "%6d %8d %s\n",
this->AstId(i).ToInt(),
FullCodeGenerator::PcField::decode(pc_and_state),
FullCodeGenerator::State2String(
@@ -11118,7 +11161,7 @@
DeoptimizationInputData::cast(this->deoptimization_data());
data->DeoptimizationInputDataPrint(out);
}
- PrintF("\n");
+ PrintF(out, "\n");
if (is_crankshafted()) {
SafepointTable table(this);
@@ -11126,7 +11169,7 @@
for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i);
PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
- table.PrintEntry(i);
+ table.PrintEntry(i, out);
PrintF(out, " (sp -> fp)");
SafepointEntry entry = table.GetEntry(i);
if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
@@ -11167,7 +11210,7 @@
#endif
}
- PrintF("RelocInfo (size = %d)\n", relocation_size());
+ PrintF(out, "RelocInfo (size = %d)\n", relocation_size());
for (RelocIterator it(this); !it.done(); it.next()) {
it.rinfo()->Print(GetIsolate(), out);
}
@@ -11453,11 +11496,11 @@
for (int i = 0; i < indices.length(); ++i) {
JSObject::EnqueueChangeRecord(
- self, "deleted", isolate->factory()->Uint32ToString(indices[i]),
+ self, "delete", isolate->factory()->Uint32ToString(indices[i]),
old_values[i]);
}
JSObject::EnqueueChangeRecord(
- self, "updated", isolate->factory()->length_string(),
+ self, "update", isolate->factory()->length_string(),
old_length_handle);
EndPerformSplice(self);
@@ -11805,6 +11848,8 @@
}
}
+ bool dictionary_elements_in_chain =
+ object->map()->DictionaryElementsInPrototypeChainOnly();
Handle<JSObject> real_receiver = object;
if (skip_hidden_prototypes) {
@@ -11837,6 +11882,14 @@
ASSERT(new_map->prototype() == *value);
real_receiver->set_map(*new_map);
+ if (!dictionary_elements_in_chain &&
+ new_map->DictionaryElementsInPrototypeChainOnly()) {
+ // If the prototype chain didn't previously have element callbacks, then
+ // KeyedStoreICs need to be cleared to ensure any that involve this
+ // map go generic.
+ object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
+ }
+
heap->ClearInstanceofCache();
ASSERT(size == object->Size());
return value;
@@ -12492,6 +12545,7 @@
Handle<Object> value,
PropertyAttributes attr,
StrictModeFlag strict_mode,
+ bool check_prototype,
SetPropertyMode set_mode) {
if (object->HasExternalArrayElements()) {
if (!value->IsNumber() && !value->IsUndefined()) {
@@ -12504,7 +12558,8 @@
}
CALL_HEAP_FUNCTION(
object->GetIsolate(),
- object->SetElement(index, *value, attr, strict_mode, true, set_mode),
+ object->SetElement(index, *value, attr, strict_mode, check_prototype,
+ set_mode),
Object);
}
@@ -12603,26 +12658,26 @@
CHECK(new_length_handle->ToArrayIndex(&new_length));
BeginPerformSplice(Handle<JSArray>::cast(self));
- EnqueueChangeRecord(self, "new", name, old_value);
- EnqueueChangeRecord(self, "updated", isolate->factory()->length_string(),
+ EnqueueChangeRecord(self, "add", name, old_value);
+ EnqueueChangeRecord(self, "update", isolate->factory()->length_string(),
old_length_handle);
EndPerformSplice(Handle<JSArray>::cast(self));
Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
EnqueueSpliceRecord(Handle<JSArray>::cast(self), old_length, deleted,
new_length - old_length);
} else {
- EnqueueChangeRecord(self, "new", name, old_value);
+ EnqueueChangeRecord(self, "add", name, old_value);
}
} else if (old_value->IsTheHole()) {
- EnqueueChangeRecord(self, "reconfigured", name, old_value);
+ EnqueueChangeRecord(self, "reconfigure", name, old_value);
} else {
Handle<Object> new_value = Object::GetElement(isolate, self, index);
bool value_changed = !old_value->SameValue(*new_value);
if (old_attributes != new_attributes) {
if (!value_changed) old_value = isolate->factory()->the_hole_value();
- EnqueueChangeRecord(self, "reconfigured", name, old_value);
+ EnqueueChangeRecord(self, "reconfigure", name, old_value);
} else if (value_changed) {
- EnqueueChangeRecord(self, "updated", name, old_value);
+ EnqueueChangeRecord(self, "update", name, old_value);
}
}
@@ -12825,9 +12880,11 @@
}
if (from_kind == to_kind) return this;
-
- MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
- if (maybe_failure->IsFailure()) return maybe_failure;
+ // Don't update the site if to_kind isn't fast
+ if (IsFastElementsKind(to_kind)) {
+ MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ }
Isolate* isolate = GetIsolate();
if (elements() == isolate->heap()->empty_fixed_array() ||
diff --git a/src/objects.h b/src/objects.h
index aa91ac1..3105579 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -869,14 +869,6 @@
class StringStream;
class Type;
-struct ValueInfo : public Malloced {
- ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { }
- InstanceType type;
- Object* ptr;
- const char* str;
- double number;
-};
-
// A template-ized version of the IsXXX functions.
template <class C> inline bool Is(Object* obj);
@@ -2376,6 +2368,7 @@
Handle<Object> value,
PropertyAttributes attr,
StrictModeFlag strict_mode,
+ bool check_prototype = true,
SetPropertyMode set_mode = SET_PROPERTY);
// A Failure object is returned if GC is needed.
@@ -5337,6 +5330,8 @@
DECLARE_VERIFIER(Code)
void ClearInlineCaches();
+ void ClearInlineCaches(Kind kind);
+
void ClearTypeFeedbackCells(Heap* heap);
BailoutId TranslatePcOffsetToAstId(uint32_t pc_offset);
@@ -5373,7 +5368,7 @@
return GetCodeAgeStub(isolate, kNotExecutedCodeAge, NO_MARKING_PARITY);
}
- void PrintDeoptLocation(int bailout_id);
+ void PrintDeoptLocation(FILE* out, int bailout_id);
bool CanDeoptAt(Address pc);
#ifdef VERIFY_HEAP
@@ -5509,6 +5504,8 @@
private:
friend class RelocIterator;
+ void ClearInlineCaches(Kind* kind);
+
// Code aging
byte* FindCodeAgeSequence();
static void GetCodeAgeAndParity(Code* code, Age* age,
@@ -5800,6 +5797,10 @@
static bool IsValidElementsTransition(ElementsKind from_kind,
ElementsKind to_kind);
+ // Returns true if the current map doesn't have DICTIONARY_ELEMENTS but if a
+ // map with DICTIONARY_ELEMENTS was found in the prototype chain.
+ bool DictionaryElementsInPrototypeChainOnly();
+
inline bool HasTransitionArray();
inline bool HasElementsTransition();
inline Map* elements_transition_map();
diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
index e9c0254..fbc4f05 100644
--- a/src/optimizing-compiler-thread.cc
+++ b/src/optimizing-compiler-thread.cc
@@ -346,23 +346,23 @@
void OptimizingCompilerThread::AddToOsrBuffer(RecompileJob* job) {
ASSERT(!IsOptimizerThread());
// Find the next slot that is empty or has a stale job.
+ RecompileJob* stale = NULL;
while (true) {
- RecompileJob* stale = osr_buffer_[osr_buffer_cursor_];
+ stale = osr_buffer_[osr_buffer_cursor_];
if (stale == NULL || stale->IsWaitingForInstall()) break;
osr_buffer_cursor_ = (osr_buffer_cursor_ + 1) % osr_buffer_capacity_;
}
// Add to found slot and dispose the evicted job.
- RecompileJob* evicted = osr_buffer_[osr_buffer_cursor_];
- if (evicted != NULL) {
- ASSERT(evicted->IsWaitingForInstall());
- CompilationInfo* info = evicted->info();
+ if (stale != NULL) {
+ ASSERT(stale->IsWaitingForInstall());
+ CompilationInfo* info = stale->info();
if (FLAG_trace_osr) {
PrintF("[COSR - Discarded ");
info->closure()->PrintName();
PrintF(", AST id %d]\n", info->osr_ast_id().ToInt());
}
- DisposeRecompileJob(evicted, false);
+ DisposeRecompileJob(stale, false);
}
osr_buffer_[osr_buffer_cursor_] = job;
osr_buffer_cursor_ = (osr_buffer_cursor_ + 1) % osr_buffer_capacity_;
diff --git a/src/parser.cc b/src/parser.cc
index d84649d..0b1bf63 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -2623,13 +2623,10 @@
if (for_of != NULL) {
Factory* heap_factory = isolate()->factory();
- Handle<String> iterator_str = heap_factory->InternalizeOneByteString(
- STATIC_ASCII_VECTOR(".iterator"));
- Handle<String> result_str = heap_factory->InternalizeOneByteString(
- STATIC_ASCII_VECTOR(".result"));
- Variable* iterator =
- top_scope_->DeclarationScope()->NewTemporary(iterator_str);
- Variable* result = top_scope_->DeclarationScope()->NewTemporary(result_str);
+ Variable* iterator = top_scope_->DeclarationScope()->NewTemporary(
+ heap_factory->dot_iterator_string());
+ Variable* result = top_scope_->DeclarationScope()->NewTemporary(
+ heap_factory->dot_result_string());
Expression* assign_iterator;
Expression* next_result;
@@ -3663,61 +3660,7 @@
// Update the scope information before the pre-parsing bailout.
int literal_index = current_function_state_->NextMaterializedLiteralIndex();
- // Allocate a fixed array to hold all the object literals.
- Handle<JSArray> array =
- isolate()->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
- isolate()->factory()->SetElementsCapacityAndLength(
- array, values->length(), values->length());
-
- // Fill in the literals.
- Heap* heap = isolate()->heap();
- bool is_simple = true;
- int depth = 1;
- bool is_holey = false;
- for (int i = 0, n = values->length(); i < n; i++) {
- MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
- if (m_literal != NULL && m_literal->depth() + 1 > depth) {
- depth = m_literal->depth() + 1;
- }
- Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
- if (boilerplate_value->IsTheHole()) {
- is_holey = true;
- } else if (boilerplate_value->IsUninitialized()) {
- is_simple = false;
- JSObject::SetOwnElement(
- array, i, handle(Smi::FromInt(0), isolate()), kNonStrictMode);
- } else {
- JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode);
- }
- }
-
- Handle<FixedArrayBase> element_values(array->elements());
-
- // Simple and shallow arrays can be lazily copied, we transform the
- // elements array to a copy-on-write array.
- if (is_simple && depth == 1 && values->length() > 0 &&
- array->HasFastSmiOrObjectElements()) {
- element_values->set_map(heap->fixed_cow_array_map());
- }
-
- // Remember both the literal's constant values as well as the ElementsKind
- // in a 2-element FixedArray.
- Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(2, TENURED);
-
- ElementsKind kind = array->GetElementsKind();
- kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
-
- literals->set(0, Smi::FromInt(kind));
- literals->set(1, *element_values);
-
- return factory()->NewArrayLiteral(
- literals, values, literal_index, is_simple, depth, pos);
-}
-
-
-bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
- return property != NULL &&
- property->kind() != ObjectLiteral::Property::PROTOTYPE;
+ return factory()->NewArrayLiteral(values, literal_index, pos);
}
@@ -3764,89 +3707,6 @@
}
-Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
- if (expression->AsLiteral() != NULL) {
- return expression->AsLiteral()->value();
- }
- if (CompileTimeValue::IsCompileTimeValue(expression)) {
- return CompileTimeValue::GetValue(isolate(), expression);
- }
- return isolate()->factory()->uninitialized_value();
-}
-
-
-void Parser::BuildObjectLiteralConstantProperties(
- ZoneList<ObjectLiteral::Property*>* properties,
- Handle<FixedArray> constant_properties,
- bool* is_simple,
- bool* fast_elements,
- int* depth,
- bool* may_store_doubles) {
- int position = 0;
- // Accumulate the value in local variables and store it at the end.
- bool is_simple_acc = true;
- int depth_acc = 1;
- uint32_t max_element_index = 0;
- uint32_t elements = 0;
- for (int i = 0; i < properties->length(); i++) {
- ObjectLiteral::Property* property = properties->at(i);
- if (!IsBoilerplateProperty(property)) {
- is_simple_acc = false;
- continue;
- }
- MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
- if (m_literal != NULL && m_literal->depth() >= depth_acc) {
- depth_acc = m_literal->depth() + 1;
- }
-
- // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
- // value for COMPUTED properties, the real value is filled in at
- // runtime. The enumeration order is maintained.
- Handle<Object> key = property->key()->value();
- Handle<Object> value = GetBoilerplateValue(property->value());
-
- // Ensure objects that may, at any point in time, contain fields with double
- // representation are always treated as nested objects. This is true for
- // computed fields (value is undefined), and smi and double literals
- // (value->IsNumber()).
- // TODO(verwaest): Remove once we can store them inline.
- if (FLAG_track_double_fields &&
- (value->IsNumber() || value->IsUninitialized())) {
- *may_store_doubles = true;
- }
-
- is_simple_acc = is_simple_acc && !value->IsUninitialized();
-
- // Keep track of the number of elements in the object literal and
- // the largest element index. If the largest element index is
- // much larger than the number of elements, creating an object
- // literal with fast elements will be a waste of space.
- uint32_t element_index = 0;
- if (key->IsString()
- && Handle<String>::cast(key)->AsArrayIndex(&element_index)
- && element_index > max_element_index) {
- max_element_index = element_index;
- elements++;
- } else if (key->IsSmi()) {
- int key_value = Smi::cast(*key)->value();
- if (key_value > 0
- && static_cast<uint32_t>(key_value) > max_element_index) {
- max_element_index = key_value;
- }
- elements++;
- }
-
- // Add name, value pair to the fixed array.
- constant_properties->set(position++, *key);
- constant_properties->set(position++, *value);
- }
- *fast_elements =
- (max_element_index <= 32) || ((2 * elements) >= max_element_index);
- *is_simple = is_simple_acc;
- *depth = depth_acc;
-}
-
-
Expression* Parser::ParseObjectLiteral(bool* ok) {
// ObjectLiteral ::
// '{' (
@@ -3915,7 +3775,7 @@
// Specification only allows zero parameters for get and one for set.
ObjectLiteral::Property* property =
factory()->NewObjectLiteralProperty(is_getter, value, next_pos);
- if (IsBoilerplateProperty(property)) {
+ if (ObjectLiteral::IsBoilerplateProperty(property)) {
number_of_boilerplate_properties++;
}
properties->Add(property, zone());
@@ -3987,7 +3847,9 @@
}
// Count CONSTANT or COMPUTED properties to maintain the enumeration order.
- if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
+ if (ObjectLiteral::IsBoilerplateProperty(property)) {
+ number_of_boilerplate_properties++;
+ }
properties->Add(property, zone());
// TODO(1240767): Consider allowing trailing comma.
@@ -4003,26 +3865,9 @@
// Computation of literal_index must happen before pre parse bailout.
int literal_index = current_function_state_->NextMaterializedLiteralIndex();
- Handle<FixedArray> constant_properties = isolate()->factory()->NewFixedArray(
- number_of_boilerplate_properties * 2, TENURED);
-
- bool is_simple = true;
- bool fast_elements = true;
- int depth = 1;
- bool may_store_doubles = false;
- BuildObjectLiteralConstantProperties(properties,
- constant_properties,
- &is_simple,
- &fast_elements,
- &depth,
- &may_store_doubles);
- return factory()->NewObjectLiteral(constant_properties,
- properties,
+ return factory()->NewObjectLiteral(properties,
literal_index,
- is_simple,
- fast_elements,
- depth,
- may_store_doubles,
+ number_of_boilerplate_properties,
has_function,
pos);
}
@@ -4252,9 +4097,8 @@
// in a temporary variable, a definition that is used by "yield"
// expressions. Presence of a variable for the generator object in the
// FunctionState indicates that this function is a generator.
- Handle<String> tempname = isolate()->factory()->InternalizeOneByteString(
- STATIC_ASCII_VECTOR(".generator_object"));
- Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
+ Variable* temp = top_scope_->DeclarationScope()->NewTemporary(
+ isolate()->factory()->dot_generator_object_string());
function_state.set_generator_object_variable(temp);
}
diff --git a/src/parser.h b/src/parser.h
index 79ce68b..f5ad311 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -653,25 +653,6 @@
Expression* ParseObjectLiteral(bool* ok);
Expression* ParseRegExpLiteral(bool seen_equal, bool* ok);
- // Populate the constant properties fixed array for a materialized object
- // literal.
- void BuildObjectLiteralConstantProperties(
- ZoneList<ObjectLiteral::Property*>* properties,
- Handle<FixedArray> constants,
- bool* is_simple,
- bool* fast_elements,
- int* depth,
- bool* may_store_doubles);
-
- // Decide if a property should be in the object boilerplate.
- bool IsBoilerplateProperty(ObjectLiteral::Property* property);
- // If the expression is a literal, return the literal value;
- // if the expression is a materialized literal and is simple return a
- // compile time value as encoded by CompileTimeValue::GetValue().
- // Otherwise, return undefined literal as the placeholder
- // in the object literal boilerplate.
- Handle<Object> GetBoilerplateValue(Expression* expression);
-
// Initialize the components of a for-in / for-of statement.
void InitializeForEachStatement(ForEachStatement* stmt,
Expression* each,
diff --git a/src/rewriter.cc b/src/rewriter.cc
index 70b362f..ba35284 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -263,7 +263,7 @@
ZoneList<Statement*>* body = function->body();
if (!body->is_empty()) {
Variable* result = scope->NewTemporary(
- info->isolate()->factory()->result_string());
+ info->isolate()->factory()->dot_result_string());
Processor processor(result, info->zone());
processor.Process(body);
if (processor.HasStackOverflow()) return false;
diff --git a/src/runtime.cc b/src/runtime.cc
index dd36a53..c9f152f 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -1620,7 +1620,7 @@
Handle<Object> new_value(
GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
if (!new_value->SameValue(*old_value)) {
- JSObject::EnqueueChangeRecord(obj, "prototype",
+ JSObject::EnqueueChangeRecord(obj, "setPrototype",
isolate->factory()->proto_string(),
old_value);
}
@@ -5031,12 +5031,12 @@
RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
- LookupResult result(isolate);
- js_object->LocalLookupRealNamedProperty(*name, &result);
+ LookupResult lookup(isolate);
+ js_object->LocalLookupRealNamedProperty(*name, &lookup);
// Special case for callback properties.
- if (result.IsPropertyCallbacks()) {
- Object* callback = result.GetCallbackObject();
+ if (lookup.IsPropertyCallbacks()) {
+ Handle<Object> callback(lookup.GetCallbackObject(), isolate);
// To be compatible with Safari we do not change the value on API objects
// in Object.defineProperty(). Firefox disagrees here, and actually changes
// the value.
@@ -5047,13 +5047,13 @@
// setter to update the value instead.
// TODO(mstarzinger): So far this only works if property attributes don't
// change, this should be fixed once we cleanup the underlying code.
- if (callback->IsForeign() && result.GetAttributes() == attr) {
+ if (callback->IsForeign() && lookup.GetAttributes() == attr) {
Handle<Object> result_object =
JSObject::SetPropertyWithCallback(js_object,
- handle(callback, isolate),
+ callback,
name,
obj_value,
- handle(result.holder()),
+ handle(lookup.holder()),
kStrictMode);
RETURN_IF_EMPTY_HANDLE(isolate, result_object);
return *result_object;
@@ -5066,8 +5066,8 @@
// map. The current version of SetObjectProperty does not handle attributes
// correctly in the case where a property is a field and is reset with
// new attributes.
- if (result.IsFound() &&
- (attr != result.GetAttributes() || result.IsPropertyCallbacks())) {
+ if (lookup.IsFound() &&
+ (attr != lookup.GetAttributes() || lookup.IsPropertyCallbacks())) {
// New attributes - normalize to avoid writing to instance descriptor
if (js_object->IsJSGlobalProxy()) {
// Since the result is a property, the prototype will exist so
@@ -5083,11 +5083,12 @@
return *result;
}
- return Runtime::ForceSetObjectProperty(isolate,
- js_object,
- name,
- obj_value,
- attr);
+ Handle<Object> result = Runtime::ForceSetObjectProperty(isolate, js_object,
+ name,
+ obj_value,
+ attr);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
@@ -5121,49 +5122,36 @@
}
-MaybeObject* Runtime::SetObjectPropertyOrFail(
- Isolate* isolate,
- Handle<Object> object,
- Handle<Object> key,
- Handle<Object> value,
- PropertyAttributes attr,
- StrictModeFlag strict_mode) {
- CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
- SetObjectProperty(isolate, object, key, value, attr, strict_mode));
-}
-
-
-MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
- Handle<Object> object,
- Handle<Object> key,
- Handle<Object> value,
- PropertyAttributes attr,
- StrictModeFlag strict_mode) {
+Handle<Object> Runtime::SetObjectProperty(Isolate* isolate,
+ Handle<Object> object,
+ Handle<Object> key,
+ Handle<Object> value,
+ PropertyAttributes attr,
+ StrictModeFlag strict_mode) {
SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
- HandleScope scope(isolate);
if (object->IsUndefined() || object->IsNull()) {
Handle<Object> args[2] = { key, object };
Handle<Object> error =
isolate->factory()->NewTypeError("non_object_property_store",
HandleVector(args, 2));
- return isolate->Throw(*error);
+ isolate->Throw(*error);
+ return Handle<Object>();
}
if (object->IsJSProxy()) {
bool has_pending_exception = false;
Handle<Object> name_object = key->IsSymbol()
? key : Execution::ToString(isolate, key, &has_pending_exception);
- if (has_pending_exception) return Failure::Exception();
+ if (has_pending_exception) return Handle<Object>(); // exception
Handle<Name> name = Handle<Name>::cast(name_object);
- Handle<Object> result = JSReceiver::SetProperty(
- Handle<JSProxy>::cast(object), name, value, attr, strict_mode);
- RETURN_IF_EMPTY_HANDLE(isolate, result);
- return *result;
+ return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value,
+ attr,
+ strict_mode);
}
// If the object isn't a JavaScript object, we ignore the store.
- if (!object->IsJSObject()) return *value;
+ if (!object->IsJSObject()) return value;
Handle<JSObject> js_object = Handle<JSObject>::cast(object);
@@ -5178,7 +5166,7 @@
// string does nothing with the assignment then we can ignore such
// assignments.
if (js_object->IsStringObjectWithCharacterAt(index)) {
- return *value;
+ return value;
}
js_object->ValidateElements();
@@ -5187,15 +5175,16 @@
bool has_exception;
Handle<Object> number =
Execution::ToNumber(isolate, value, &has_exception);
- if (has_exception) return Failure::Exception();
+ if (has_exception) return Handle<Object>(); // exception
value = number;
}
}
- MaybeObject* result = js_object->SetElement(
- index, *value, attr, strict_mode, true, set_mode);
+ Handle<Object> result = JSObject::SetElement(js_object, index, value, attr,
+ strict_mode,
+ true,
+ set_mode);
js_object->ValidateElements();
- if (result->IsFailure()) return result;
- return *value;
+ return result.is_null() ? result : value;
}
if (key->IsName()) {
@@ -5206,48 +5195,41 @@
bool has_exception;
Handle<Object> number =
Execution::ToNumber(isolate, value, &has_exception);
- if (has_exception) return Failure::Exception();
+ if (has_exception) return Handle<Object>(); // exception
value = number;
}
}
- MaybeObject* result = js_object->SetElement(
- index, *value, attr, strict_mode, true, set_mode);
- if (result->IsFailure()) return result;
+ return JSObject::SetElement(js_object, index, value, attr, strict_mode,
+ true,
+ set_mode);
} else {
if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
- Handle<Object> result =
- JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
- RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
}
- return *value;
}
// Call-back into JavaScript to convert the key to a string.
bool has_pending_exception = false;
Handle<Object> converted =
Execution::ToString(isolate, key, &has_pending_exception);
- if (has_pending_exception) return Failure::Exception();
+ if (has_pending_exception) return Handle<Object>(); // exception
Handle<String> name = Handle<String>::cast(converted);
if (name->AsArrayIndex(&index)) {
- return js_object->SetElement(
- index, *value, attr, strict_mode, true, set_mode);
+ return JSObject::SetElement(js_object, index, value, attr, strict_mode,
+ true,
+ set_mode);
} else {
- Handle<Object> result =
- JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
- RETURN_IF_EMPTY_HANDLE(isolate, result);
- return *result;
+ return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
}
}
-MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
- Handle<JSObject> js_object,
- Handle<Object> key,
- Handle<Object> value,
- PropertyAttributes attr) {
- HandleScope scope(isolate);
-
+Handle<Object> Runtime::ForceSetObjectProperty(Isolate* isolate,
+ Handle<JSObject> js_object,
+ Handle<Object> key,
+ Handle<Object> value,
+ PropertyAttributes attr) {
// Check if the given key is an array index.
uint32_t index;
if (key->ToArrayIndex(&index)) {
@@ -5259,24 +5241,24 @@
// string does nothing with the assignment then we can ignore such
// assignments.
if (js_object->IsStringObjectWithCharacterAt(index)) {
- return *value;
+ return value;
}
- return js_object->SetElement(
- index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
+ return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
+ false,
+ DEFINE_PROPERTY);
}
if (key->IsName()) {
Handle<Name> name = Handle<Name>::cast(key);
if (name->AsArrayIndex(&index)) {
- return js_object->SetElement(
- index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
+ return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
+ false,
+ DEFINE_PROPERTY);
} else {
if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
- Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
- js_object, name, value, attr);
- RETURN_IF_EMPTY_HANDLE(isolate, result);
- return *result;
+ return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name,
+ value, attr);
}
}
@@ -5284,17 +5266,16 @@
bool has_pending_exception = false;
Handle<Object> converted =
Execution::ToString(isolate, key, &has_pending_exception);
- if (has_pending_exception) return Failure::Exception();
+ if (has_pending_exception) return Handle<Object>(); // exception
Handle<String> name = Handle<String>::cast(converted);
if (name->AsArrayIndex(&index)) {
- return js_object->SetElement(
- index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
+ return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
+ false,
+ DEFINE_PROPERTY);
} else {
- Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
- js_object, name, value, attr);
- RETURN_IF_EMPTY_HANDLE(isolate, result);
- return *result;
+ return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name, value,
+ attr);
}
}
@@ -5343,12 +5324,12 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
- SealHandleScope shs(isolate);
+ HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
- Handle<Object> object = args.at<Object>(0);
- Handle<Object> key = args.at<Object>(1);
- Handle<Object> value = args.at<Object>(2);
+ CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
RUNTIME_ASSERT(
(unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
@@ -5362,12 +5343,12 @@
strict_mode = strict_mode_flag;
}
- return Runtime::SetObjectProperty(isolate,
- object,
- key,
- value,
- attributes,
- strict_mode);
+ Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
+ value,
+ attributes,
+ strict_mode);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
@@ -5388,10 +5369,10 @@
SealHandleScope shs(isolate);
RUNTIME_ASSERT(args.length() == 1);
- Handle<Object> object = args.at<Object>(0);
+ CONVERT_ARG_CHECKED(Object, object, 0);
if (object->IsJSFunction()) {
- JSFunction* func = JSFunction::cast(*object);
+ JSFunction* func = JSFunction::cast(object);
func->shared()->set_native(true);
}
return isolate->heap()->undefined_value();
@@ -6194,6 +6175,7 @@
MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
Isolate* isolate,
String* s,
+ String::Encoding result_encoding,
int length,
int input_string_length,
unibrow::Mapping<Converter, 128>* mapping) {
@@ -6209,7 +6191,7 @@
// might break in the future if we implement more context and locale
// dependent upper/lower conversions.
Object* o;
- { MaybeObject* maybe_o = s->IsOneByteRepresentation()
+ { MaybeObject* maybe_o = result_encoding == String::ONE_BYTE_ENCODING
? isolate->heap()->AllocateRawOneByteString(length)
: isolate->heap()->AllocateRawTwoByteString(length);
if (!maybe_o->ToObject(&o)) return maybe_o;
@@ -6217,6 +6199,8 @@
String* result = String::cast(o);
bool has_changed_character = false;
+ DisallowHeapAllocation no_gc;
+
// Convert all characters to upper case, assuming that they will fit
// in the buffer
Access<ConsStringIteratorOp> op(
@@ -6225,6 +6209,10 @@
unibrow::uchar chars[Converter::kMaxWidth];
// We can assume that the string is not empty
uc32 current = stream.GetNext();
+ // y with umlauts is the only character that stops fitting into one-byte
+ // when converting to uppercase.
+ static const uc32 yuml_code = 0xff;
+ bool ignore_yuml = result->IsSeqTwoByteString() || Converter::kIsToLower;
for (int i = 0; i < length;) {
bool has_next = stream.HasMore();
uc32 next = has_next ? stream.GetNext() : 0;
@@ -6233,13 +6221,14 @@
// The case conversion of this character is the character itself.
result->Set(i, current);
i++;
- } else if (char_length == 1) {
+ } else if (char_length == 1 && (ignore_yuml || current != yuml_code)) {
// Common case: converting the letter resulted in one character.
ASSERT(static_cast<uc32>(chars[0]) != current);
result->Set(i, chars[0]);
has_changed_character = true;
i++;
} else if (length == input_string_length) {
+ bool found_yuml = (current == yuml_code);
// We've assumed that the result would be as long as the
// input but here is a character that converts to several
// characters. No matter, we calculate the exact length
@@ -6259,6 +6248,7 @@
int current_length = i + char_length + next_length;
while (stream.HasMore()) {
current = stream.GetNext();
+ found_yuml |= (current == yuml_code);
// NOTE: we use 0 as the next character here because, while
// the next character may affect what a character converts to,
// it does not in any case affect the length of what it convert
@@ -6271,8 +6261,10 @@
return Failure::OutOfMemoryException(0x13);
}
}
- // Try again with the real length.
- return Smi::FromInt(current_length);
+ // Try again with the real length. Return signed if we need
+ // to allocate a two-byte string for y-umlaut to uppercase.
+ return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length)
+ : Smi::FromInt(current_length);
} else {
for (int j = 0; j < char_length; j++) {
result->Set(i, chars[j]);
@@ -6318,121 +6310,108 @@
}
-enum AsciiCaseConversion {
- ASCII_TO_LOWER,
- ASCII_TO_UPPER
-};
+#ifdef DEBUG
+static bool CheckFastAsciiConvert(char* dst,
+ char* src,
+ int length,
+ bool changed,
+ bool is_to_lower) {
+ bool expected_changed = false;
+ for (int i = 0; i < length; i++) {
+ if (dst[i] == src[i]) continue;
+ expected_changed = true;
+ if (is_to_lower) {
+ ASSERT('A' <= src[i] && src[i] <= 'Z');
+ ASSERT(dst[i] == src[i] + ('a' - 'A'));
+ } else {
+ ASSERT('a' <= src[i] && src[i] <= 'z');
+ ASSERT(dst[i] == src[i] - ('a' - 'A'));
+ }
+ }
+ return (expected_changed == changed);
+}
+#endif
-template <AsciiCaseConversion dir>
-struct FastAsciiConverter {
- static bool Convert(char* dst, char* src, int length, bool* changed_out) {
+template<class Converter>
+static bool FastAsciiConvert(char* dst,
+ char* src,
+ int length,
+ bool* changed_out) {
#ifdef DEBUG
char* saved_dst = dst;
char* saved_src = src;
#endif
- // We rely on the distance between upper and lower case letters
- // being a known power of 2.
- ASSERT('a' - 'A' == (1 << 5));
- // Boundaries for the range of input characters than require conversion.
- const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
- const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
- bool changed = false;
- uintptr_t or_acc = 0;
- char* const limit = src + length;
+ DisallowHeapAllocation no_gc;
+ // We rely on the distance between upper and lower case letters
+ // being a known power of 2.
+ ASSERT('a' - 'A' == (1 << 5));
+ // Boundaries for the range of input characters than require conversion.
+ static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
+ static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
+ bool changed = false;
+ uintptr_t or_acc = 0;
+ char* const limit = src + length;
#ifdef V8_HOST_CAN_READ_UNALIGNED
- // Process the prefix of the input that requires no conversion one
- // (machine) word at a time.
- while (src <= limit - sizeof(uintptr_t)) {
- uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
- or_acc |= w;
- if (AsciiRangeMask(w, lo, hi) != 0) {
- changed = true;
- break;
- }
- *reinterpret_cast<uintptr_t*>(dst) = w;
- src += sizeof(uintptr_t);
- dst += sizeof(uintptr_t);
+ // Process the prefix of the input that requires no conversion one
+ // (machine) word at a time.
+ while (src <= limit - sizeof(uintptr_t)) {
+ uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
+ or_acc |= w;
+ if (AsciiRangeMask(w, lo, hi) != 0) {
+ changed = true;
+ break;
}
- // Process the remainder of the input performing conversion when
- // required one word at a time.
- while (src <= limit - sizeof(uintptr_t)) {
- uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
- or_acc |= w;
- uintptr_t m = AsciiRangeMask(w, lo, hi);
- // The mask has high (7th) bit set in every byte that needs
- // conversion and we know that the distance between cases is
- // 1 << 5.
- *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
- src += sizeof(uintptr_t);
- dst += sizeof(uintptr_t);
- }
-#endif
- // Process the last few bytes of the input (or the whole input if
- // unaligned access is not supported).
- while (src < limit) {
- char c = *src;
- or_acc |= c;
- if (lo < c && c < hi) {
- c ^= (1 << 5);
- changed = true;
- }
- *dst = c;
- ++src;
- ++dst;
- }
- if ((or_acc & kAsciiMask) != 0) {
- return false;
- }
-#ifdef DEBUG
- CheckConvert(saved_dst, saved_src, length, changed);
-#endif
- *changed_out = changed;
- return true;
+ *reinterpret_cast<uintptr_t*>(dst) = w;
+ src += sizeof(uintptr_t);
+ dst += sizeof(uintptr_t);
}
-
-#ifdef DEBUG
- static void CheckConvert(char* dst, char* src, int length, bool changed) {
- bool expected_changed = false;
- for (int i = 0; i < length; i++) {
- if (dst[i] == src[i]) continue;
- expected_changed = true;
- if (dir == ASCII_TO_LOWER) {
- ASSERT('A' <= src[i] && src[i] <= 'Z');
- ASSERT(dst[i] == src[i] + ('a' - 'A'));
- } else {
- ASSERT(dir == ASCII_TO_UPPER);
- ASSERT('a' <= src[i] && src[i] <= 'z');
- ASSERT(dst[i] == src[i] - ('a' - 'A'));
- }
- }
- ASSERT(expected_changed == changed);
+ // Process the remainder of the input performing conversion when
+ // required one word at a time.
+ while (src <= limit - sizeof(uintptr_t)) {
+ uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
+ or_acc |= w;
+ uintptr_t m = AsciiRangeMask(w, lo, hi);
+ // The mask has high (7th) bit set in every byte that needs
+ // conversion and we know that the distance between cases is
+ // 1 << 5.
+ *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
+ src += sizeof(uintptr_t);
+ dst += sizeof(uintptr_t);
}
#endif
-};
+ // Process the last few bytes of the input (or the whole input if
+ // unaligned access is not supported).
+ while (src < limit) {
+ char c = *src;
+ or_acc |= c;
+ if (lo < c && c < hi) {
+ c ^= (1 << 5);
+ changed = true;
+ }
+ *dst = c;
+ ++src;
+ ++dst;
+ }
+ if ((or_acc & kAsciiMask) != 0) {
+ return false;
+ }
+ ASSERT(CheckFastAsciiConvert(
+ saved_dst, saved_src, length, changed, Converter::kIsToLower));
-struct ToLowerTraits {
- typedef unibrow::ToLowercase UnibrowConverter;
-
- typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
-};
-
-
-struct ToUpperTraits {
- typedef unibrow::ToUppercase UnibrowConverter;
-
- typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
-};
+ *changed_out = changed;
+ return true;
+}
} // namespace
-template <typename ConvertTraits>
+template <class Converter>
MUST_USE_RESULT static MaybeObject* ConvertCase(
Arguments args,
Isolate* isolate,
- unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
+ unibrow::Mapping<Converter, 128>* mapping) {
SealHandleScope shs(isolate);
CONVERT_ARG_CHECKED(String, s, 0);
s = s->TryFlattenGetString();
@@ -6454,7 +6433,7 @@
}
SeqOneByteString* result = SeqOneByteString::cast(o);
bool has_changed_character;
- bool is_ascii = ConvertTraits::AsciiConverter::Convert(
+ bool is_ascii = FastAsciiConvert<Converter>(
reinterpret_cast<char*>(result->GetChars()),
reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
length,
@@ -6465,31 +6444,35 @@
}
}
+ String::Encoding result_encoding = s->IsOneByteRepresentationUnderneath()
+ ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING;
Object* answer;
- { MaybeObject* maybe_answer =
- ConvertCaseHelper(isolate, s, length, length, mapping);
+ { MaybeObject* maybe_answer = ConvertCaseHelper(
+ isolate, s, result_encoding, length, length, mapping);
if (!maybe_answer->ToObject(&answer)) return maybe_answer;
}
if (answer->IsSmi()) {
- // Retry with correct length.
- { MaybeObject* maybe_answer =
- ConvertCaseHelper(isolate,
- s, Smi::cast(answer)->value(), length, mapping);
- if (!maybe_answer->ToObject(&answer)) return maybe_answer;
+ int new_length = Smi::cast(answer)->value();
+ if (new_length < 0) {
+ result_encoding = String::TWO_BYTE_ENCODING;
+ new_length = -new_length;
}
+ MaybeObject* maybe_answer = ConvertCaseHelper(
+ isolate, s, result_encoding, new_length, length, mapping);
+ if (!maybe_answer->ToObject(&answer)) return maybe_answer;
}
return answer;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
- return ConvertCase<ToLowerTraits>(
+ return ConvertCase(
args, isolate, isolate->runtime_state()->to_lower_mapping());
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
- return ConvertCase<ToUpperTraits>(
+ return ConvertCase(
args, isolate, isolate->runtime_state()->to_upper_mapping());
}
@@ -11349,12 +11332,12 @@
RETURN_IF_EMPTY_HANDLE_VALUE(
isolate,
- SetProperty(isolate,
- target,
- Handle<String>(scope_info->ParameterName(i)),
- value,
- NONE,
- kNonStrictMode),
+ Runtime::SetObjectProperty(isolate,
+ target,
+ Handle<String>(scope_info->ParameterName(i)),
+ value,
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
@@ -11365,12 +11348,13 @@
RETURN_IF_EMPTY_HANDLE_VALUE(
isolate,
- SetProperty(isolate,
- target,
- Handle<String>(scope_info->StackLocalName(i)),
- value,
- NONE,
- kNonStrictMode),
+ Runtime::SetObjectProperty(
+ isolate,
+ target,
+ Handle<String>(scope_info->StackLocalName(i)),
+ value,
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
@@ -11448,12 +11432,12 @@
Handle<String> key(String::cast(keys->get(i)));
RETURN_IF_EMPTY_HANDLE_VALUE(
isolate,
- SetProperty(isolate,
- target,
- key,
- GetProperty(isolate, ext, key),
- NONE,
- kNonStrictMode),
+ Runtime::SetObjectProperty(isolate,
+ target,
+ key,
+ GetProperty(isolate, ext, key),
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
}
@@ -11553,12 +11537,9 @@
if (JSReceiver::HasProperty(ext, variable_name)) {
// We don't expect this to do anything except replacing
// property value.
- SetProperty(isolate,
- ext,
- variable_name,
- new_value,
- NONE,
- kNonStrictMode);
+ Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
+ NONE,
+ kNonStrictMode);
return true;
}
}
@@ -11604,12 +11585,10 @@
Handle<String> key(String::cast(keys->get(i)));
RETURN_IF_EMPTY_HANDLE_VALUE(
isolate,
- SetProperty(isolate,
- closure_scope,
- key,
- GetProperty(isolate, ext, key),
- NONE,
- kNonStrictMode),
+ Runtime::SetObjectProperty(isolate, closure_scope, key,
+ GetProperty(isolate, ext, key),
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
}
@@ -11640,12 +11619,9 @@
Handle<JSObject> ext(JSObject::cast(context->extension()));
if (JSReceiver::HasProperty(ext, variable_name)) {
// We don't expect this to do anything except replacing property value.
- SetProperty(isolate,
- ext,
- variable_name,
- new_value,
- NONE,
- kNonStrictMode);
+ Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
+ NONE,
+ kNonStrictMode);
return true;
}
}
@@ -11666,12 +11642,9 @@
isolate->factory()->NewJSObject(isolate->object_function());
RETURN_IF_EMPTY_HANDLE_VALUE(
isolate,
- SetProperty(isolate,
- catch_scope,
- name,
- thrown_object,
- NONE,
- kNonStrictMode),
+ Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object,
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
return catch_scope;
}
@@ -12689,12 +12662,11 @@
// FunctionGetArguments can't throw an exception.
Handle<JSObject> arguments = Handle<JSObject>::cast(
Accessors::FunctionGetArguments(function));
- SetProperty(isolate,
- target,
- isolate->factory()->arguments_string(),
- arguments,
- ::NONE,
- kNonStrictMode);
+ Runtime::SetObjectProperty(isolate, target,
+ isolate->factory()->arguments_string(),
+ arguments,
+ ::NONE,
+ kNonStrictMode);
return target;
}
diff --git a/src/runtime.h b/src/runtime.h
index 55276f8..c316d40 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -776,7 +776,7 @@
Handle<Object> object,
uint32_t index);
- MUST_USE_RESULT static MaybeObject* SetObjectProperty(
+ static Handle<Object> SetObjectProperty(
Isolate* isolate,
Handle<Object> object,
Handle<Object> key,
@@ -784,15 +784,7 @@
PropertyAttributes attr,
StrictModeFlag strict_mode);
- MUST_USE_RESULT static MaybeObject* SetObjectPropertyOrFail(
- Isolate* isolate,
- Handle<Object> object,
- Handle<Object> key,
- Handle<Object> value,
- PropertyAttributes attr,
- StrictModeFlag strict_mode);
-
- MUST_USE_RESULT static MaybeObject* ForceSetObjectProperty(
+ static Handle<Object> ForceSetObjectProperty(
Isolate* isolate,
Handle<JSObject> object,
Handle<Object> key,
diff --git a/src/safepoint-table.cc b/src/safepoint-table.cc
index b565565..beecb27 100644
--- a/src/safepoint-table.cc
+++ b/src/safepoint-table.cc
@@ -83,7 +83,7 @@
}
-void SafepointTable::PrintEntry(unsigned index) const {
+void SafepointTable::PrintEntry(unsigned index, FILE* out) const {
disasm::NameConverter converter;
SafepointEntry entry = GetEntry(index);
uint8_t* bits = entry.bits();
@@ -93,25 +93,25 @@
ASSERT(IsAligned(kNumSafepointRegisters, kBitsPerByte));
const int first = kNumSafepointRegisters >> kBitsPerByteLog2;
int last = entry_size_ - 1;
- for (int i = first; i < last; i++) PrintBits(bits[i], kBitsPerByte);
+ for (int i = first; i < last; i++) PrintBits(out, bits[i], kBitsPerByte);
int last_bits = code_->stack_slots() - ((last - first) * kBitsPerByte);
- PrintBits(bits[last], last_bits);
+ PrintBits(out, bits[last], last_bits);
// Print the registers (if any).
if (!entry.HasRegisters()) return;
for (int j = 0; j < kNumSafepointRegisters; j++) {
if (entry.HasRegisterAt(j)) {
- PrintF(" | %s", converter.NameOfCPURegister(j));
+ PrintF(out, " | %s", converter.NameOfCPURegister(j));
}
}
}
}
-void SafepointTable::PrintBits(uint8_t byte, int digits) {
+void SafepointTable::PrintBits(FILE* out, uint8_t byte, int digits) {
ASSERT(digits >= 0 && digits <= kBitsPerByte);
for (int i = 0; i < digits; i++) {
- PrintF("%c", ((byte & (1 << i)) == 0) ? '0' : '1');
+ PrintF(out, "%c", ((byte & (1 << i)) == 0) ? '0' : '1');
}
}
diff --git a/src/safepoint-table.h b/src/safepoint-table.h
index fc8bf7a..ea35253 100644
--- a/src/safepoint-table.h
+++ b/src/safepoint-table.h
@@ -126,7 +126,7 @@
// Returns the entry for the given pc.
SafepointEntry FindEntry(Address pc) const;
- void PrintEntry(unsigned index) const;
+ void PrintEntry(unsigned index, FILE* out = stdout) const;
private:
static const uint8_t kNoRegisters = 0xFF;
@@ -149,7 +149,7 @@
return GetPcOffsetLocation(index) + kPcSize;
}
- static void PrintBits(uint8_t byte, int digits);
+ static void PrintBits(FILE* out, uint8_t byte, int digits);
DisallowHeapAllocation no_allocation_;
Code* code_;
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index f1ae876..04c0044 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -374,15 +374,14 @@
int end = start + local_count;
for (int i = start; i < end; ++i) {
int context_index = Context::MIN_CONTEXT_SLOTS + i - start;
- RETURN_IF_EMPTY_HANDLE_VALUE(
+ Handle<Object> result = Runtime::SetObjectProperty(
isolate,
- SetProperty(isolate,
- scope_object,
- Handle<String>(String::cast(scope_info->get(i))),
- Handle<Object>(context->get(context_index), isolate),
- ::NONE,
- kNonStrictMode),
- false);
+ scope_object,
+ Handle<String>(String::cast(scope_info->get(i))),
+ Handle<Object>(context->get(context_index), isolate),
+ ::NONE,
+ kNonStrictMode);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, false);
}
return true;
}
diff --git a/src/scopes.cc b/src/scopes.cc
index ee327fb..137ab68 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -1302,7 +1302,7 @@
void Scope::AllocateNonParameterLocal(Variable* var) {
ASSERT(var->scope() == this);
- ASSERT(!var->IsVariable(isolate_->factory()->result_string()) ||
+ ASSERT(!var->IsVariable(isolate_->factory()->dot_result_string()) ||
!var->IsStackLocal());
if (var->IsUnallocated() && MustAllocate(var)) {
if (MustAllocateInContext(var)) {
diff --git a/src/serialize.cc b/src/serialize.cc
index 3cc7053..4c89bcf 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -1668,86 +1668,71 @@
void Serializer::ObjectSerializer::VisitEmbeddedPointer(RelocInfo* rinfo) {
- Object* current = rinfo->target_object();
-
int skip = OutputRawData(rinfo->target_address_address(),
kCanReturnSkipInsteadOfSkipping);
- HowToCode representation = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
- serializer_->SerializeObject(current, representation, kStartOfObject, skip);
+ HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
+ Object* object = rinfo->target_object();
+ serializer_->SerializeObject(object, how_to_code, kStartOfObject, skip);
bytes_processed_so_far_ += rinfo->target_address_size();
}
void Serializer::ObjectSerializer::VisitExternalReference(Address* p) {
- Address references_start = reinterpret_cast<Address>(p);
- int skip = OutputRawData(references_start, kCanReturnSkipInsteadOfSkipping);
-
+ int skip = OutputRawData(reinterpret_cast<Address>(p),
+ kCanReturnSkipInsteadOfSkipping);
sink_->Put(kExternalReference + kPlain + kStartOfObject, "ExternalRef");
sink_->PutInt(skip, "SkipB4ExternalRef");
- int reference_id = serializer_->EncodeExternalReference(*p);
- sink_->PutInt(reference_id, "reference id");
+ Address target = *p;
+ sink_->PutInt(serializer_->EncodeExternalReference(target), "reference id");
bytes_processed_so_far_ += kPointerSize;
}
void Serializer::ObjectSerializer::VisitExternalReference(RelocInfo* rinfo) {
- Address references_start = rinfo->target_address_address();
- int skip = OutputRawData(references_start, kCanReturnSkipInsteadOfSkipping);
-
- Address current = rinfo->target_reference();
- int representation = rinfo->IsCodedSpecially() ?
- kFromCode + kStartOfObject : kPlain + kStartOfObject;
- sink_->Put(kExternalReference + representation, "ExternalRef");
+ int skip = OutputRawData(rinfo->target_address_address(),
+ kCanReturnSkipInsteadOfSkipping);
+ HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
+ sink_->Put(kExternalReference + how_to_code + kStartOfObject, "ExternalRef");
sink_->PutInt(skip, "SkipB4ExternalRef");
- int reference_id = serializer_->EncodeExternalReference(current);
- sink_->PutInt(reference_id, "reference id");
+ Address target = rinfo->target_reference();
+ sink_->PutInt(serializer_->EncodeExternalReference(target), "reference id");
bytes_processed_so_far_ += rinfo->target_address_size();
}
void Serializer::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) {
- Address target_start = rinfo->target_address_address();
- int skip = OutputRawData(target_start, kCanReturnSkipInsteadOfSkipping);
- Address target = rinfo->target_address();
- uint32_t encoding = serializer_->EncodeExternalReference(target);
- CHECK(target == NULL ? encoding == 0 : encoding != 0);
- int representation;
- // Can't use a ternary operator because of gcc.
- if (rinfo->IsCodedSpecially()) {
- representation = kStartOfObject + kFromCode;
- } else {
- representation = kStartOfObject + kPlain;
- }
- sink_->Put(kExternalReference + representation, "ExternalReference");
+ int skip = OutputRawData(rinfo->target_address_address(),
+ kCanReturnSkipInsteadOfSkipping);
+ HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
+ sink_->Put(kExternalReference + how_to_code + kStartOfObject, "ExternalRef");
sink_->PutInt(skip, "SkipB4ExternalRef");
- sink_->PutInt(encoding, "reference id");
+ Address target = rinfo->target_address();
+ sink_->PutInt(serializer_->EncodeExternalReference(target), "reference id");
bytes_processed_so_far_ += rinfo->target_address_size();
}
void Serializer::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) {
- CHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
- Address target_start = rinfo->target_address_address();
- int skip = OutputRawData(target_start, kCanReturnSkipInsteadOfSkipping);
- Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
- serializer_->SerializeObject(target, kFromCode, kInnerPointer, skip);
+ int skip = OutputRawData(rinfo->target_address_address(),
+ kCanReturnSkipInsteadOfSkipping);
+ Code* object = Code::GetCodeFromTargetAddress(rinfo->target_address());
+ serializer_->SerializeObject(object, kFromCode, kInnerPointer, skip);
bytes_processed_so_far_ += rinfo->target_address_size();
}
void Serializer::ObjectSerializer::VisitCodeEntry(Address entry_address) {
- Code* target = Code::cast(Code::GetObjectFromEntryAddress(entry_address));
int skip = OutputRawData(entry_address, kCanReturnSkipInsteadOfSkipping);
- serializer_->SerializeObject(target, kPlain, kInnerPointer, skip);
+ Code* object = Code::cast(Code::GetObjectFromEntryAddress(entry_address));
+ serializer_->SerializeObject(object, kPlain, kInnerPointer, skip);
bytes_processed_so_far_ += kPointerSize;
}
void Serializer::ObjectSerializer::VisitCell(RelocInfo* rinfo) {
- ASSERT(rinfo->rmode() == RelocInfo::CELL);
- Cell* cell = Cell::cast(rinfo->target_cell());
int skip = OutputRawData(rinfo->pc(), kCanReturnSkipInsteadOfSkipping);
- serializer_->SerializeObject(cell, kPlain, kInnerPointer, skip);
+ Cell* object = Cell::cast(rinfo->target_cell());
+ serializer_->SerializeObject(object, kPlain, kInnerPointer, skip);
}
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 1ec00d4..1bc4b13 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -202,22 +202,6 @@
}
-Handle<Code> StubCache::ComputeLoadGlobal(Handle<Name> name,
- Handle<JSObject> receiver,
- Handle<GlobalObject> holder,
- Handle<PropertyCell> cell,
- bool is_dont_delete) {
- Handle<Code> stub = FindIC(name, receiver, Code::LOAD_IC);
- if (!stub.is_null()) return stub;
-
- LoadStubCompiler compiler(isolate_);
- Handle<Code> ic =
- compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
- HeapObject::UpdateMapCodeCache(receiver, name, ic);
- return ic;
-}
-
-
Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
Handle<Name> name =
@@ -262,35 +246,6 @@
}
-Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name,
- Handle<GlobalObject> receiver,
- Handle<PropertyCell> cell,
- Handle<Object> value,
- StrictModeFlag strict_mode) {
- Handle<Type> union_type = PropertyCell::UpdatedType(cell, value);
- bool is_constant = union_type->IsConstant();
- StoreGlobalStub stub(strict_mode, is_constant);
-
- Handle<Code> code = FindIC(
- name, Handle<JSObject>::cast(receiver),
- Code::STORE_IC, stub.GetExtraICState());
- if (!code.is_null()) return code;
-
- // Replace the placeholder cell and global object map with the actual global
- // cell and receiver map.
- Handle<Map> meta_map(isolate_->heap()->meta_map());
- Handle<Object> receiver_map(receiver->map(), isolate_);
- code = stub.GetCodeCopyFromTemplate(isolate_);
- code->ReplaceNthObject(1, *meta_map, *receiver_map);
- Handle<Map> cell_map(isolate_->heap()->global_property_cell_map());
- code->ReplaceNthObject(1, *cell_map, *cell);
-
- HeapObject::UpdateMapCodeCache(receiver, name, code);
-
- return code;
-}
-
-
#define CALL_LOGGER_TAG(kind, type) \
(kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
@@ -1141,7 +1096,10 @@
masm_.GetCode(&desc);
Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
#ifdef ENABLE_DISASSEMBLER
- if (FLAG_print_code_stubs) code->Disassemble(name);
+ if (FLAG_print_code_stubs) {
+ CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
+ code->Disassemble(name, trace_scope.file());
+ }
#endif
return code;
}
@@ -1596,7 +1554,6 @@
Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
Code::StubType type,
Handle<Name> name) {
- ASSERT(type != Code::NORMAL);
Code::Flags flags = Code::ComputeFlags(
Code::HANDLER, MONOMORPHIC, extra_state(), type, kind);
Handle<Code> code = GetCodeWithFlags(flags, name);
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 42685b2..9a82785 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -105,47 +105,8 @@
Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
Handle<JSObject> object);
- Handle<Code> ComputeLoadGlobal(Handle<Name> name,
- Handle<JSObject> object,
- Handle<GlobalObject> holder,
- Handle<PropertyCell> cell,
- bool is_dont_delete);
-
// ---
- Handle<Code> ComputeKeyedLoadField(Handle<Name> name,
- Handle<JSObject> object,
- Handle<JSObject> holder,
- PropertyIndex field_index,
- Representation representation);
-
- Handle<Code> ComputeKeyedLoadCallback(
- Handle<Name> name,
- Handle<JSObject> object,
- Handle<JSObject> holder,
- Handle<ExecutableAccessorInfo> callback);
-
- Handle<Code> ComputeKeyedLoadCallback(
- Handle<Name> name,
- Handle<JSObject> object,
- Handle<JSObject> holder,
- const CallOptimization& call_optimization);
-
- Handle<Code> ComputeKeyedLoadConstant(Handle<Name> name,
- Handle<JSObject> object,
- Handle<JSObject> holder,
- Handle<Object> value);
-
- Handle<Code> ComputeKeyedLoadInterceptor(Handle<Name> name,
- Handle<JSObject> object,
- Handle<JSObject> holder);
-
- Handle<Code> ComputeStoreGlobal(Handle<Name> name,
- Handle<GlobalObject> object,
- Handle<PropertyCell> cell,
- Handle<Object> value,
- StrictModeFlag strict_mode);
-
Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
diff --git a/src/typedarray.js b/src/typedarray.js
index f2b5d2d..d435803 100644
--- a/src/typedarray.js
+++ b/src/typedarray.js
@@ -48,65 +48,72 @@
endmacro
macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
- function NAMEConstructor(arg1, arg2, arg3) {
- function ConstructByArrayBuffer(obj, buffer, byteOffset, length) {
- var offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length")
+ function NAMEConstructByArrayBuffer(obj, buffer, byteOffset, length) {
+ var bufferByteLength = buffer.byteLength;
+ var offset;
+ if (IS_UNDEFINED(byteOffset)) {
+ offset = 0;
+ } else {
+ offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length");
if (offset % ELEMENT_SIZE !== 0) {
throw MakeRangeError("invalid_typed_array_alignment",
"start offset", "NAME", ELEMENT_SIZE);
}
- var bufferByteLength = %ArrayBufferGetByteLength(buffer);
if (offset > bufferByteLength) {
throw MakeRangeError("invalid_typed_array_offset");
}
-
- var newByteLength;
- var newLength;
- if (IS_UNDEFINED(length)) {
- if (bufferByteLength % ELEMENT_SIZE !== 0) {
- throw MakeRangeError("invalid_typed_array_alignment",
- "byte length", "NAME", ELEMENT_SIZE);
- }
- newByteLength = bufferByteLength - offset;
- newLength = newByteLength / ELEMENT_SIZE;
- } else {
- var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
- newByteLength = newLength * ELEMENT_SIZE;
- }
- if (offset + newByteLength > bufferByteLength) {
- throw MakeRangeError("invalid_typed_array_length");
- }
- %TypedArrayInitialize(obj, ARRAY_ID, buffer, offset, newByteLength);
}
- function ConstructByLength(obj, length) {
- var l = ToPositiveInteger(length, "invalid_typed_array_length");
- var byteLength = l * ELEMENT_SIZE;
- var buffer = new $ArrayBuffer(byteLength);
- %TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength);
+ var newByteLength;
+ var newLength;
+ if (IS_UNDEFINED(length)) {
+ if (bufferByteLength % ELEMENT_SIZE !== 0) {
+ throw MakeRangeError("invalid_typed_array_alignment",
+ "byte length", "NAME", ELEMENT_SIZE);
+ }
+ newByteLength = bufferByteLength - offset;
+ newLength = newByteLength / ELEMENT_SIZE;
+ } else {
+ var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
+ newByteLength = newLength * ELEMENT_SIZE;
}
+ if (offset + newByteLength > bufferByteLength) {
+ throw MakeRangeError("invalid_typed_array_length");
+ }
+ %TypedArrayInitialize(obj, ARRAY_ID, buffer, offset, newByteLength);
+ }
- function ConstructByArrayLike(obj, arrayLike) {
- var length = arrayLike.length;
- var l = ToPositiveInteger(length, "invalid_typed_array_length");
- if(!%TypedArrayInitializeFromArrayLike(obj, ARRAY_ID, arrayLike, l)) {
- for (var i = 0; i < l; i++) {
- // It is crucial that we let any execptions from arrayLike[i]
- // propagate outside the function.
- obj[i] = arrayLike[i];
- }
+ function NAMEConstructByLength(obj, length) {
+ var l = IS_UNDEFINED(length) ?
+ 0 : ToPositiveInteger(length, "invalid_typed_array_length");
+ var byteLength = l * ELEMENT_SIZE;
+ var buffer = new $ArrayBuffer(byteLength);
+ %TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength);
+ }
+
+ function NAMEConstructByArrayLike(obj, arrayLike) {
+ var length = arrayLike.length;
+ var l = ToPositiveInteger(length, "invalid_typed_array_length");
+ if(!%TypedArrayInitializeFromArrayLike(obj, ARRAY_ID, arrayLike, l)) {
+ for (var i = 0; i < l; i++) {
+ // It is crucial that we let any execptions from arrayLike[i]
+ // propagate outside the function.
+ obj[i] = arrayLike[i];
}
}
+ }
+
+ function NAMEConstructor(arg1, arg2, arg3) {
if (%_IsConstructCall()) {
if (IS_ARRAYBUFFER(arg1)) {
- ConstructByArrayBuffer(this, arg1, arg2, arg3);
+ NAMEConstructByArrayBuffer(this, arg1, arg2, arg3);
} else if (IS_NUMBER(arg1) || IS_STRING(arg1) ||
IS_BOOLEAN(arg1) || IS_UNDEFINED(arg1)) {
- ConstructByLength(this, arg1);
+ NAMEConstructByLength(this, arg1);
} else {
- ConstructByArrayLike(this, arg1);
+ NAMEConstructByArrayLike(this, arg1);
}
} else {
throw MakeTypeError("constructor_not_function", ["NAME"])
@@ -284,7 +291,6 @@
));
}
-
macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
SetupTypedArray (global.NAME, NAMEConstructor, ELEMENT_SIZE);
endmacro
@@ -301,7 +307,8 @@
throw MakeTypeError('data_view_not_array_buffer', []);
}
var bufferByteLength = %ArrayBufferGetByteLength(buffer);
- var offset = ToPositiveInteger(byteOffset, 'invalid_data_view_offset');
+ var offset = IS_UNDEFINED(byteOffset) ?
+ 0 : ToPositiveInteger(byteOffset, 'invalid_data_view_offset');
if (offset > bufferByteLength) {
throw MakeRangeError('invalid_data_view_offset');
}
diff --git a/src/unicode.h b/src/unicode.h
index f1dcad0..6ba61d0 100644
--- a/src/unicode.h
+++ b/src/unicode.h
@@ -235,6 +235,7 @@
};
struct ToLowercase {
static const int kMaxWidth = 3;
+ static const bool kIsToLower = true;
static int Convert(uchar c,
uchar n,
uchar* result,
@@ -242,6 +243,7 @@
};
struct ToUppercase {
static const int kMaxWidth = 3;
+ static const bool kIsToLower = false;
static int Convert(uchar c,
uchar n,
uchar* result,
diff --git a/src/utils.h b/src/utils.h
index 062019a..3a0936e 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -1083,7 +1083,7 @@
// The strange typing in ASSERT is necessary to avoid stupid warnings, see:
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43680
ASSERT(static_cast<int>(element) < static_cast<int>(sizeof(T) * CHAR_BIT));
- return 1 << element;
+ return static_cast<T>(1) << element;
}
T bits_;
diff --git a/src/v8.cc b/src/v8.cc
index 62330c3..fc6c56d 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -206,6 +206,7 @@
if (FLAG_concurrent_recompilation &&
(FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs)) {
FLAG_concurrent_recompilation = false;
+ FLAG_concurrent_osr = false;
PrintF("Concurrent recompilation has been disabled for tracing.\n");
}
@@ -229,8 +230,9 @@
if (FLAG_concurrent_recompilation &&
SystemThreadManager::NumberOfParallelSystemThreads(
- SystemThreadManager::PARALLEL_RECOMPILATION) == 0) {
+ SystemThreadManager::CONCURRENT_RECOMPILATION) == 0) {
FLAG_concurrent_recompilation = false;
+ FLAG_concurrent_osr = false;
}
Sampler::SetUp();
diff --git a/src/version.cc b/src/version.cc
index 83c0852..621ac34 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 23
-#define BUILD_NUMBER 0
+#define BUILD_NUMBER 1
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 99e2ad4..00bfa4e 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -1357,6 +1357,24 @@
}
+void Assembler::movb(const Operand& dst, Immediate imm) {
+ EnsureSpace ensure_space(this);
+ emit_optional_rex_32(dst);
+ emit(0xC6);
+ emit_operand(0x0, dst);
+ emit(static_cast<byte>(imm.value_));
+}
+
+
+void Assembler::movw(Register dst, const Operand& src) {
+ EnsureSpace ensure_space(this);
+ emit(0x66);
+ emit_optional_rex_32(dst, src);
+ emit(0x8B);
+ emit_operand(dst, src);
+}
+
+
void Assembler::movw(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
emit(0x66);
@@ -1366,6 +1384,17 @@
}
+void Assembler::movw(const Operand& dst, Immediate imm) {
+ EnsureSpace ensure_space(this);
+ emit(0x66);
+ emit_optional_rex_32(dst);
+ emit(0xC7);
+ emit_operand(0x0, dst);
+ emit(static_cast<byte>(imm.value_ & 0xff));
+ emit(static_cast<byte>(imm.value_ >> 8));
+}
+
+
void Assembler::movl(Register dst, const Operand& src) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(dst, src);
@@ -1456,34 +1485,22 @@
// This method must not be used with heap object references. The stored
// address is not GC safe. Use the handle version instead.
ASSERT(rmode > RelocInfo::LAST_GCED_ENUM);
- EnsureSpace ensure_space(this);
- emit_rex_64(dst);
- emit(0xB8 | dst.low_bits());
- emitp(value, rmode);
-}
-
-
-void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) {
- // Non-relocatable values might not need a 64-bit representation.
- ASSERT(RelocInfo::IsNone(rmode));
- if (is_uint32(value)) {
- movl(dst, Immediate(static_cast<int32_t>(value)));
- } else if (is_int32(value)) {
- movq(dst, Immediate(static_cast<int32_t>(value)));
+ if (RelocInfo::IsNone(rmode)) {
+ movq(dst, reinterpret_cast<int64_t>(value));
} else {
- // Value cannot be represented by 32 bits, so do a full 64 bit immediate
- // value.
EnsureSpace ensure_space(this);
emit_rex_64(dst);
emit(0xB8 | dst.low_bits());
- emitq(value);
+ emitp(value, rmode);
}
}
-void Assembler::movq(Register dst, ExternalReference ref) {
- Address value = reinterpret_cast<Address>(ref.address());
- movq(dst, value, RelocInfo::EXTERNAL_REFERENCE);
+void Assembler::movq(Register dst, int64_t value) {
+ EnsureSpace ensure_space(this);
+ emit_rex_64(dst);
+ emit(0xB8 | dst.low_bits());
+ emitq(value);
}
@@ -1521,21 +1538,13 @@
void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode mode) {
AllowDeferredHandleDereference using_raw_address;
- // If there is no relocation info, emit the value of the handle efficiently
- // (possibly using less that 8 bytes for the value).
- if (RelocInfo::IsNone(mode)) {
- // There is no possible reason to store a heap pointer without relocation
- // info, so it must be a smi.
- ASSERT(value->IsSmi());
- movq(dst, reinterpret_cast<int64_t>(*value), RelocInfo::NONE64);
- } else {
- EnsureSpace ensure_space(this);
- ASSERT(value->IsHeapObject());
- ASSERT(!isolate()->heap()->InNewSpace(*value));
- emit_rex_64(dst);
- emit(0xB8 | dst.low_bits());
- emitp(value.location(), mode);
- }
+ ASSERT(!RelocInfo::IsNone(mode));
+ EnsureSpace ensure_space(this);
+ ASSERT(value->IsHeapObject());
+ ASSERT(!isolate()->heap()->InNewSpace(*value));
+ emit_rex_64(dst);
+ emit(0xB8 | dst.low_bits());
+ emitp(value.location(), mode);
}
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index 584b3a5..c64112d 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -694,10 +694,13 @@
void movb(Register dst, const Operand& src);
void movb(Register dst, Immediate imm);
void movb(const Operand& dst, Register src);
+ void movb(const Operand& dst, Immediate imm);
// Move the low 16 bits of a 64-bit register value to a 16-bit
// memory location.
+ void movw(Register dst, const Operand& src);
void movw(const Operand& dst, Register src);
+ void movw(const Operand& dst, Immediate imm);
void movl(Register dst, Register src);
void movl(Register dst, const Operand& src);
@@ -719,12 +722,10 @@
// Move sign extended immediate to memory location.
void movq(const Operand& dst, Immediate value);
- // Instructions to load a 64-bit immediate into a register.
- // All 64-bit immediates must have a relocation mode.
+ // Loads a pointer into a register with a relocation mode.
void movq(Register dst, void* ptr, RelocInfo::Mode rmode);
- void movq(Register dst, int64_t value, RelocInfo::Mode rmode);
- // Moves the address of the external reference into the register.
- void movq(Register dst, ExternalReference ext);
+ // Loads a 64-bit immediate into a register.
+ void movq(Register dst, int64_t value);
void movq(Register dst, Handle<Object> handle, RelocInfo::Mode rmode);
void movsxbq(Register dst, const Operand& src);
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index f65b25c..30cd314 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -158,7 +158,7 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
ExternalReference debug_step_in_fp =
ExternalReference::debug_step_in_fp_address(masm->isolate());
- __ movq(kScratchRegister, debug_step_in_fp);
+ __ Move(kScratchRegister, debug_step_in_fp);
__ cmpq(Operand(kScratchRegister, 0), Immediate(0));
__ j(not_equal, &rt_call);
#endif
@@ -600,8 +600,7 @@
// the stub returns.
__ subq(Operand(rsp, 0), Immediate(5));
__ Pushad();
- __ movq(arg_reg_2,
- ExternalReference::isolate_address(masm->isolate()));
+ __ Move(arg_reg_2, ExternalReference::isolate_address(masm->isolate()));
__ movq(arg_reg_1, Operand(rsp, kNumSafepointRegisters * kPointerSize));
{ // NOLINT
FrameScope scope(masm, StackFrame::MANUAL);
@@ -633,7 +632,7 @@
// save/restore the registers without worrying about which of them contain
// pointers.
__ Pushad();
- __ movq(arg_reg_2, ExternalReference::isolate_address(masm->isolate()));
+ __ Move(arg_reg_2, ExternalReference::isolate_address(masm->isolate()));
__ movq(arg_reg_1, Operand(rsp, kNumSafepointRegisters * kPointerSize));
__ subq(arg_reg_1, Immediate(Assembler::kShortCallInstructionLength));
{ // NOLINT
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 93bc2b9..be8160b 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -631,7 +631,7 @@
// rcx = TranscendentalCache::hash(double value).
ExternalReference cache_array =
ExternalReference::transcendental_cache_array_address(masm->isolate());
- __ movq(rax, cache_array);
+ __ Move(rax, cache_array);
int cache_array_index =
type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]);
__ movq(rax, Operand(rax, cache_array_index));
@@ -959,7 +959,7 @@
Label continue_sqrt, continue_rsqrt, not_plus_half;
// Test for 0.5.
// Load double_scratch with 0.5.
- __ movq(scratch, V8_UINT64_C(0x3FE0000000000000), RelocInfo::NONE64);
+ __ movq(scratch, V8_UINT64_C(0x3FE0000000000000));
__ movq(double_scratch, scratch);
// Already ruled out NaNs for exponent.
__ ucomisd(double_scratch, double_exponent);
@@ -969,7 +969,7 @@
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
// According to IEEE-754, double-precision -Infinity has the highest
// 12 bits set and the lowest 52 bits cleared.
- __ movq(scratch, V8_UINT64_C(0xFFF0000000000000), RelocInfo::NONE64);
+ __ movq(scratch, V8_UINT64_C(0xFFF0000000000000));
__ movq(double_scratch, scratch);
__ ucomisd(double_scratch, double_base);
// Comparing -Infinity with NaN results in "unordered", which sets the
@@ -1001,7 +1001,7 @@
// case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
// According to IEEE-754, double-precision -Infinity has the highest
// 12 bits set and the lowest 52 bits cleared.
- __ movq(scratch, V8_UINT64_C(0xFFF0000000000000), RelocInfo::NONE64);
+ __ movq(scratch, V8_UINT64_C(0xFFF0000000000000));
__ movq(double_scratch, scratch);
__ ucomisd(double_scratch, double_base);
// Comparing -Infinity with NaN results in "unordered", which sets the
@@ -1873,9 +1873,9 @@
Immediate(1));
// Argument 7: Start (high end) of backtracking stack memory area.
- __ movq(kScratchRegister, address_of_regexp_stack_memory_address);
+ __ Move(kScratchRegister, address_of_regexp_stack_memory_address);
__ movq(r9, Operand(kScratchRegister, 0));
- __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
+ __ Move(kScratchRegister, address_of_regexp_stack_memory_size);
__ addq(r9, Operand(kScratchRegister, 0));
__ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r9);
@@ -2810,9 +2810,9 @@
// PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the
// stack is known to be aligned. This function takes one argument which is
// passed in register.
- __ movq(arg_reg_2, ExternalReference::isolate_address(masm->isolate()));
+ __ Move(arg_reg_2, ExternalReference::isolate_address(masm->isolate()));
__ movq(arg_reg_1, rax);
- __ movq(kScratchRegister,
+ __ Move(kScratchRegister,
ExternalReference::perform_gc_function(masm->isolate()));
__ call(kScratchRegister);
}
@@ -2834,7 +2834,7 @@
// Return result in single register (rax).
__ movq(rcx, r14); // argc.
__ movq(rdx, r15); // argv.
- __ movq(r8, ExternalReference::isolate_address(masm->isolate()));
+ __ Move(r8, ExternalReference::isolate_address(masm->isolate()));
} else {
ASSERT_EQ(2, result_size_);
// Pass a pointer to the result location as the first argument.
@@ -2842,14 +2842,14 @@
// Pass a pointer to the Arguments object as the second argument.
__ movq(rdx, r14); // argc.
__ movq(r8, r15); // argv.
- __ movq(r9, ExternalReference::isolate_address(masm->isolate()));
+ __ Move(r9, ExternalReference::isolate_address(masm->isolate()));
}
#else // _WIN64
// GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
__ movq(rdi, r14); // argc.
__ movq(rsi, r15); // argv.
- __ movq(rdx, ExternalReference::isolate_address(masm->isolate()));
+ __ Move(rdx, ExternalReference::isolate_address(masm->isolate()));
#endif
__ call(rbx);
// Result is in rax - do not destroy this register!
@@ -3030,9 +3030,7 @@
// Scratch register is neither callee-save, nor an argument register on any
// platform. It's free to use at this point.
// Cannot use smi-register for loading yet.
- __ movq(kScratchRegister,
- reinterpret_cast<uint64_t>(Smi::FromInt(marker)),
- RelocInfo::NONE64);
+ __ movq(kScratchRegister, Smi::FromInt(marker), RelocInfo::NONE64);
__ push(kScratchRegister); // context slot
__ push(kScratchRegister); // function slot
// Save callee-saved registers (X64/Win64 calling conventions).
@@ -3139,7 +3137,7 @@
__ pop(rbx);
__ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
__ j(not_equal, ¬_outermost_js_2);
- __ movq(kScratchRegister, js_entry_sp);
+ __ Move(kScratchRegister, js_entry_sp);
__ movq(Operand(kScratchRegister, 0), Immediate(0));
__ bind(¬_outermost_js_2);
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 390ec7c..afe0e3b 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -213,7 +213,7 @@
__ j(zero, &valid_result);
__ fstp(0); // Drop result in st(0).
int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000);
- __ movq(rcx, kNaNValue, RelocInfo::NONE64);
+ __ movq(rcx, kNaNValue);
__ movq(Operand(rsp, kPointerSize), rcx);
__ movsd(xmm0, Operand(rsp, kPointerSize));
__ jmp(&return_result);
@@ -338,7 +338,7 @@
STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
Label loop, entry, convert_hole;
- __ movq(r15, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE64);
+ __ movq(r15, BitCast<int64_t, uint64_t>(kHoleNanInt64));
// r15: the-hole NaN
__ jmp(&entry);
@@ -440,7 +440,7 @@
__ movq(FieldOperand(r11, FixedArray::kLengthOffset), r14);
// Prepare for conversion loop.
- __ movq(rsi, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE64);
+ __ movq(rsi, BitCast<int64_t, uint64_t>(kHoleNanInt64));
__ LoadRoot(rdi, Heap::kTheHoleValueRootIndex);
// rsi: the-hole NaN
// rdi: pointer to the-hole
@@ -635,7 +635,7 @@
Label done;
- __ movq(kScratchRegister, ExternalReference::math_exp_constants(0));
+ __ Move(kScratchRegister, ExternalReference::math_exp_constants(0));
__ movsd(double_scratch, Operand(kScratchRegister, 0 * kDoubleSize));
__ xorpd(result, result);
__ ucomisd(double_scratch, input);
@@ -654,10 +654,10 @@
__ and_(temp2, Immediate(0x7ff));
__ shr(temp1, Immediate(11));
__ mulsd(double_scratch, Operand(kScratchRegister, 5 * kDoubleSize));
- __ movq(kScratchRegister, ExternalReference::math_exp_log_table());
+ __ Move(kScratchRegister, ExternalReference::math_exp_log_table());
__ shl(temp1, Immediate(52));
__ or_(temp1, Operand(kScratchRegister, temp2, times_8, 0));
- __ movq(kScratchRegister, ExternalReference::math_exp_constants(0));
+ __ Move(kScratchRegister, ExternalReference::math_exp_constants(0));
__ subsd(double_scratch, input);
__ movsd(input, double_scratch);
__ subsd(result, double_scratch);
diff --git a/src/x64/debug-x64.cc b/src/x64/debug-x64.cc
index 6612242..5ddf69a 100644
--- a/src/x64/debug-x64.cc
+++ b/src/x64/debug-x64.cc
@@ -132,7 +132,7 @@
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ Set(rax, 0); // No arguments (argc == 0).
- __ movq(rbx, ExternalReference::debug_break(masm->isolate()));
+ __ Move(rbx, ExternalReference::debug_break(masm->isolate()));
CEntryStub ceb(1);
__ CallStub(&ceb);
@@ -172,7 +172,7 @@
// overwritten by the address of DebugBreakXXX.
ExternalReference after_break_target =
ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
- __ movq(kScratchRegister, after_break_target);
+ __ Move(kScratchRegister, after_break_target);
__ jmp(Operand(kScratchRegister, 0));
}
@@ -319,7 +319,7 @@
ExternalReference restarter_frame_function_slot =
ExternalReference(Debug_Address::RestarterFrameFunctionPointer(),
masm->isolate());
- __ movq(rax, restarter_frame_function_slot);
+ __ Move(rax, restarter_frame_function_slot);
__ movq(Operand(rax, 0), Immediate(0));
// We do not know our frame height, but set rsp based on rbp.
diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc
index 70d410d..667561b 100644
--- a/src/x64/disasm-x64.cc
+++ b/src/x64/disasm-x64.cc
@@ -1565,9 +1565,15 @@
} else {
AppendToBuffer("mov%c ", operand_size_code());
data += PrintRightOperand(data);
- int32_t imm = *reinterpret_cast<int32_t*>(data);
- AppendToBuffer(",0x%x", imm);
- data += 4;
+ if (operand_size() == OPERAND_WORD_SIZE) {
+ int16_t imm = *reinterpret_cast<int16_t*>(data);
+ AppendToBuffer(",0x%x", imm);
+ data += 2;
+ } else {
+ int32_t imm = *reinterpret_cast<int32_t*>(data);
+ AppendToBuffer(",0x%x", imm);
+ data += 4;
+ }
}
}
break;
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 4a99287..468ed8c 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -315,9 +315,7 @@
reset_value = Smi::kMaxValue;
}
__ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
- __ movq(kScratchRegister,
- reinterpret_cast<uint64_t>(Smi::FromInt(reset_value)),
- RelocInfo::NONE64);
+ __ Move(kScratchRegister, Smi::FromInt(reset_value));
__ movq(FieldOperand(rbx, Cell::kValueOffset), kScratchRegister);
}
@@ -1597,6 +1595,9 @@
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
+
+ int depth = 1;
+ expr->BuildConstantProperties(isolate(), &depth);
Handle<FixedArray> constant_properties = expr->constant_properties();
int flags = expr->fast_elements()
? ObjectLiteral::kFastElements
@@ -1606,7 +1607,7 @@
: ObjectLiteral::kNoFlags;
int properties_count = constant_properties->length() / 2;
if ((FLAG_track_double_fields && expr->may_store_doubles()) ||
- expr->depth() > 1 || Serializer::enabled() ||
+ depth > 1 || Serializer::enabled() ||
flags != ObjectLiteral::kFastElements ||
properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
__ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
@@ -1725,6 +1726,8 @@
void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral");
+ int depth = 1;
+ expr->BuildConstantElements(isolate(), &depth);
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements();
@@ -1751,8 +1754,7 @@
DONT_TRACK_ALLOCATION_SITE,
length);
__ CallStub(&stub);
- } else if (expr->depth() > 1 ||
- Serializer::enabled() ||
+ } else if (depth > 1 || Serializer::enabled() ||
length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
@@ -4379,14 +4381,47 @@
PrepareForBailoutForId(prop->LoadId(), TOS_REG);
}
- // Call ToNumber only if operand is not a smi.
- Label no_conversion;
+ // Inline smi case if we are in a loop.
+ Label done, stub_call;
+ JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
- __ JumpIfSmi(rax, &no_conversion, Label::kNear);
+ Label slow;
+ patch_site.EmitJumpIfNotSmi(rax, &slow, Label::kNear);
+
+ // Save result for postfix expressions.
+ if (expr->is_postfix()) {
+ if (!context()->IsEffect()) {
+ // Save the result on the stack. If we have a named or keyed property
+ // we store the result under the receiver that is currently on top
+ // of the stack.
+ switch (assign_type) {
+ case VARIABLE:
+ __ push(rax);
+ break;
+ case NAMED_PROPERTY:
+ __ movq(Operand(rsp, kPointerSize), rax);
+ break;
+ case KEYED_PROPERTY:
+ __ movq(Operand(rsp, 2 * kPointerSize), rax);
+ break;
+ }
+ }
+ }
+
+ SmiOperationExecutionMode mode;
+ mode.Add(PRESERVE_SOURCE_REGISTER);
+ mode.Add(BAILOUT_ON_NO_OVERFLOW);
+ if (expr->op() == Token::INC) {
+ __ SmiAddConstant(rax, rax, Smi::FromInt(1), mode, &done, Label::kNear);
+ } else {
+ __ SmiSubConstant(rax, rax, Smi::FromInt(1), mode, &done, Label::kNear);
+ }
+ __ jmp(&stub_call, Label::kNear);
+ __ bind(&slow);
}
+
ToNumberStub convert_stub;
__ CallStub(&convert_stub);
- __ bind(&no_conversion);
// Save result for postfix expressions.
if (expr->is_postfix()) {
@@ -4408,34 +4443,11 @@
}
}
- // Inline smi case if we are in a loop.
- Label done, stub_call;
- JumpPatchSite patch_site(masm_);
-
- if (ShouldInlineSmiCase(expr->op())) {
- if (expr->op() == Token::INC) {
- __ SmiAddConstant(rax, rax, Smi::FromInt(1));
- } else {
- __ SmiSubConstant(rax, rax, Smi::FromInt(1));
- }
- __ j(overflow, &stub_call, Label::kNear);
- // We could eliminate this smi check if we split the code at
- // the first smi check before calling ToNumber.
- patch_site.EmitJumpIfSmi(rax, &done, Label::kNear);
-
- __ bind(&stub_call);
- // Call stub. Undo operation first.
- if (expr->op() == Token::INC) {
- __ SmiSubConstant(rax, rax, Smi::FromInt(1));
- } else {
- __ SmiAddConstant(rax, rax, Smi::FromInt(1));
- }
- }
-
// Record position before stub call.
SetSourcePosition(expr->position());
// Call stub for +1/-1.
+ __ bind(&stub_call);
__ movq(rdx, rax);
__ Move(rax, Smi::FromInt(1));
BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 15f410c..721ae1d 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -609,6 +609,21 @@
__ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
__ j(not_equal, fast_double);
}
+
+ // HOLECHECK: guards "A[i] = V"
+ // We have to go to the runtime if the current value is the hole because
+ // there may be a callback on the element
+ Label holecheck_passed1;
+ __ movq(kScratchRegister, FieldOperand(rbx,
+ rcx,
+ times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ CompareRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &holecheck_passed1);
+ __ JumpIfDictionaryInPrototypeChain(rdx, rdi, kScratchRegister, slow);
+
+ __ bind(&holecheck_passed1);
+
// Smi stores don't require further checks.
Label non_smi_value;
__ JumpIfNotSmi(rax, &non_smi_value);
@@ -648,6 +663,15 @@
__ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
__ j(not_equal, slow);
}
+
+ // HOLECHECK: guards "A[i] double hole?"
+ // We have to see if the double version of the hole is present. If so
+ // go to the runtime.
+ uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
+ __ cmpl(FieldOperand(rbx, rcx, times_8, offset), Immediate(kHoleNanUpper32));
+ __ j(not_equal, &fast_double_without_map_check);
+ __ JumpIfDictionaryInPrototypeChain(rdx, rdi, kScratchRegister, slow);
+
__ bind(&fast_double_without_map_check);
__ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
&transition_double_elements);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 5c6a580..ba186a8 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -157,7 +157,7 @@
#endif
__ push(rax);
__ Set(rax, slots);
- __ movq(kScratchRegister, kSlotsZapValue, RelocInfo::NONE64);
+ __ movq(kScratchRegister, kSlotsZapValue);
Label loop;
__ bind(&loop);
__ movq(MemOperand(rsp, rax, times_pointer_size, 0),
@@ -261,7 +261,7 @@
Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
}
if (jump_table_[i].needs_frame) {
- __ movq(kScratchRegister, ExternalReference::ForDeoptEntry(entry));
+ __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry));
if (needs_frame.is_bound()) {
__ jmp(&needs_frame);
} else {
@@ -649,7 +649,27 @@
return;
}
- ASSERT(FLAG_deopt_every_n_times == 0); // Not yet implemented on x64.
+ if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
+ ExternalReference count = ExternalReference::stress_deopt_count(isolate());
+ Label no_deopt;
+ __ pushfq();
+ __ push(rax);
+ Operand count_operand = masm()->ExternalOperand(count, kScratchRegister);
+ __ movl(rax, count_operand);
+ __ subl(rax, Immediate(1));
+ __ j(not_zero, &no_deopt, Label::kNear);
+ if (FLAG_trap_on_deopt) __ int3();
+ __ movl(rax, Immediate(FLAG_deopt_every_n_times));
+ __ movl(count_operand, rax);
+ __ pop(rax);
+ __ popfq();
+ ASSERT(frame_is_built_);
+ __ call(entry, RelocInfo::RUNTIME_ENTRY);
+ __ bind(&no_deopt);
+ __ movl(count_operand, rax);
+ __ pop(rax);
+ __ popfq();
+ }
if (info()->ShouldTrapOnDeopt()) {
Label done;
@@ -1123,7 +1143,7 @@
__ neg(reg1);
DeoptimizeIf(zero, instr->environment());
}
- __ movq(reg2, multiplier, RelocInfo::NONE64);
+ __ Set(reg2, multiplier);
// Result just fit in r64, because it's int32 * uint32.
__ imul(reg2, reg1);
@@ -1632,32 +1652,88 @@
}
-void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+Operand LCodeGen::BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding) {
+ if (index->IsConstantOperand()) {
+ int offset = ToInteger32(LConstantOperand::cast(index));
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ offset *= kUC16Size;
+ }
+ STATIC_ASSERT(kCharSize == 1);
+ return FieldOperand(string, SeqString::kHeaderSize + offset);
+ }
+ return FieldOperand(
+ string, ToRegister(index),
+ encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
+ SeqString::kHeaderSize);
+}
+
+
+void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
+ Register result = ToRegister(instr->result());
Register string = ToRegister(instr->string());
- Register index = ToRegister(instr->index());
- Register value = ToRegister(instr->value());
- String::Encoding encoding = instr->encoding();
if (FLAG_debug_code) {
- __ push(value);
- __ movq(value, FieldOperand(string, HeapObject::kMapOffset));
- __ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
+ __ push(string);
+ __ movq(string, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset));
- __ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- __ cmpq(value, Immediate(encoding == String::ONE_BYTE_ENCODING
- ? one_byte_seq_type : two_byte_seq_type));
+ __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
__ Check(equal, kUnexpectedStringType);
- __ pop(value);
+ __ pop(string);
}
+ Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
if (encoding == String::ONE_BYTE_ENCODING) {
- __ movb(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
- value);
+ __ movzxbl(result, operand);
} else {
- __ movw(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
- value);
+ __ movzxwl(result, operand);
+ }
+}
+
+
+void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
+ Register string = ToRegister(instr->string());
+
+ if (FLAG_debug_code) {
+ __ push(string);
+ __ movq(string, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset));
+
+ __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
+ __ Check(equal, kUnexpectedStringType);
+ __ pop(string);
+ }
+
+ Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (instr->value()->IsConstantOperand()) {
+ int value = ToInteger32(LConstantOperand::cast(instr->value()));
+ ASSERT_LE(0, value);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ ASSERT_LE(value, String::kMaxOneByteCharCode);
+ __ movb(operand, Immediate(value));
+ } else {
+ ASSERT_LE(value, String::kMaxUtf16CodeUnit);
+ __ movw(operand, Immediate(value));
+ }
+ } else {
+ Register value = ToRegister(instr->value());
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ movb(operand, value);
+ } else {
+ __ movw(operand, value);
+ }
}
}
@@ -3453,7 +3529,7 @@
static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5
Label done, round_to_zero, below_one_half, do_not_compensate, restore;
- __ movq(kScratchRegister, one_half, RelocInfo::NONE64);
+ __ movq(kScratchRegister, one_half);
__ movq(xmm_scratch, kScratchRegister);
__ ucomisd(xmm_scratch, input_reg);
__ j(above, &below_one_half);
@@ -3468,7 +3544,7 @@
__ jmp(&done);
__ bind(&below_one_half);
- __ movq(kScratchRegister, minus_one_half, RelocInfo::NONE64);
+ __ movq(kScratchRegister, minus_one_half);
__ movq(xmm_scratch, kScratchRegister);
__ ucomisd(xmm_scratch, input_reg);
__ j(below_equal, &round_to_zero);
@@ -3524,7 +3600,7 @@
Label done, sqrt;
// Check base for -Infinity. According to IEEE-754, double-precision
// -Infinity has the highest 12 bits set and the lowest 52 bits cleared.
- __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000), RelocInfo::NONE64);
+ __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000));
__ movq(xmm_scratch, kScratchRegister);
__ ucomisd(xmm_scratch, input_reg);
// Comparing -Infinity with NaN results in "unordered", which sets the
@@ -3632,8 +3708,7 @@
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
XMMRegister result = ToDoubleRegister(instr->result());
XMMRegister scratch4 = double_scratch0();
- __ movq(scratch3, V8_INT64_C(0x4130000000000000),
- RelocInfo::NONE64); // 1.0 x 2^20 as double
+ __ movq(scratch3, V8_INT64_C(0x4130000000000000)); // 1.0 x 2^20 as double
__ movq(scratch4, scratch3);
__ movd(result, random);
__ xorps(result, scratch4);
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index f3f202a..090f961 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -242,6 +242,10 @@
uint32_t offset,
uint32_t additional_index = 0);
+ Operand BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding);
+
void EmitIntegerMathAbs(LMathAbs* instr);
void EmitSmiMathAbs(LMathAbs* instr);
diff --git a/src/x64/lithium-gap-resolver-x64.cc b/src/x64/lithium-gap-resolver-x64.cc
index 01cfb12..6059c50 100644
--- a/src/x64/lithium-gap-resolver-x64.cc
+++ b/src/x64/lithium-gap-resolver-x64.cc
@@ -209,7 +209,7 @@
if (int_val == 0) {
__ xorps(dst, dst);
} else {
- __ movq(kScratchRegister, int_val, RelocInfo::NONE64);
+ __ Set(kScratchRegister, int_val);
__ movq(dst, kScratchRegister);
}
} else {
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 6262e7e..51e3220 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1756,14 +1756,18 @@
}
+LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
+}
+
+
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
- LOperand* string = UseRegister(instr->string());
- LOperand* index = UseRegister(instr->index());
- ASSERT(rcx.is_byte_register());
- LOperand* value = UseFixed(instr->value(), rcx);
- LSeqStringSetChar* result =
- new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
- return DefineSameAsFirst(result);
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ LOperand* value = UseRegisterOrConstantAtStart(instr->value());
+ return new(zone()) LSeqStringSetChar(string, index, value);
}
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 06cb171..717a07a 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -154,6 +154,7 @@
V(Random) \
V(RegExpLiteral) \
V(Return) \
+ V(SeqStringGetChar) \
V(SeqStringSetChar) \
V(ShiftI) \
V(SmiTag) \
@@ -1281,27 +1282,37 @@
};
+class LSeqStringGetChar V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+ LSeqStringGetChar(LOperand* string, LOperand* index) {
+ inputs_[0] = string;
+ inputs_[1] = index;
+ }
+
+ LOperand* string() const { return inputs_[0]; }
+ LOperand* index() const { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar, "seq-string-get-char")
+ DECLARE_HYDROGEN_ACCESSOR(SeqStringGetChar)
+};
+
+
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LSeqStringSetChar(String::Encoding encoding,
- LOperand* string,
+ LSeqStringSetChar(LOperand* string,
LOperand* index,
- LOperand* value) : encoding_(encoding) {
+ LOperand* value) {
inputs_[0] = string;
inputs_[1] = index;
inputs_[2] = value;
}
- String::Encoding encoding() { return encoding_; }
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
-
- private:
- String::Encoding encoding_;
};
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index a18ff0d..9ffc451 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -80,7 +80,7 @@
return Operand(kRootRegister, static_cast<int32_t>(delta));
}
}
- movq(scratch, target);
+ Move(scratch, target);
return Operand(scratch, 0);
}
@@ -98,7 +98,7 @@
if (destination.is(rax)) {
load_rax(source);
} else {
- movq(kScratchRegister, source);
+ Move(kScratchRegister, source);
movq(destination, Operand(kScratchRegister, 0));
}
}
@@ -117,7 +117,7 @@
if (source.is(rax)) {
store_rax(destination);
} else {
- movq(kScratchRegister, destination);
+ Move(kScratchRegister, destination);
movq(Operand(kScratchRegister, 0), source);
}
}
@@ -134,7 +134,7 @@
}
}
// Safe code.
- movq(destination, source);
+ Move(destination, source);
}
@@ -164,7 +164,7 @@
int64_t address = reinterpret_cast<int64_t>(source.address());
if (is_int32(address) && !Serializer::enabled()) {
if (emit_debug_code()) {
- movq(kScratchRegister, BitCast<int64_t>(kZapValue), RelocInfo::NONE64);
+ movq(kScratchRegister, kZapValue, RelocInfo::NONE64);
}
push(Immediate(static_cast<int32_t>(address)));
return;
@@ -276,20 +276,21 @@
// case the size of the new space is different between the snapshot maker
// and the running system.
if (scratch.is(object)) {
- movq(kScratchRegister, ExternalReference::new_space_mask(isolate()));
+ Move(kScratchRegister, ExternalReference::new_space_mask(isolate()));
and_(scratch, kScratchRegister);
} else {
- movq(scratch, ExternalReference::new_space_mask(isolate()));
+ Move(scratch, ExternalReference::new_space_mask(isolate()));
and_(scratch, object);
}
- movq(kScratchRegister, ExternalReference::new_space_start(isolate()));
+ Move(kScratchRegister, ExternalReference::new_space_start(isolate()));
cmpq(scratch, kScratchRegister);
j(cc, branch, distance);
} else {
ASSERT(is_int32(static_cast<int64_t>(isolate()->heap()->NewSpaceMask())));
intptr_t new_space_start =
reinterpret_cast<intptr_t>(isolate()->heap()->NewSpaceStart());
- movq(kScratchRegister, -new_space_start, RelocInfo::NONE64);
+ movq(kScratchRegister, reinterpret_cast<Address>(-new_space_start),
+ RelocInfo::NONE64);
if (scratch.is(object)) {
addq(scratch, kScratchRegister);
} else {
@@ -345,8 +346,8 @@
// Clobber clobbered input registers when running with the debug-code flag
// turned on to provoke errors.
if (emit_debug_code()) {
- movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE64);
- movq(dst, BitCast<int64_t>(kZapValue), RelocInfo::NONE64);
+ movq(value, kZapValue, RelocInfo::NONE64);
+ movq(dst, kZapValue, RelocInfo::NONE64);
}
}
@@ -379,8 +380,8 @@
// Clobber clobbered input registers when running with the debug-code flag
// turned on to provoke errors.
if (emit_debug_code()) {
- movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE64);
- movq(index, BitCast<int64_t>(kZapValue), RelocInfo::NONE64);
+ movq(value, kZapValue, RelocInfo::NONE64);
+ movq(index, kZapValue, RelocInfo::NONE64);
}
}
@@ -445,8 +446,8 @@
// Clobber clobbered registers when running with the debug-code flag
// turned on to provoke errors.
if (emit_debug_code()) {
- movq(address, BitCast<int64_t>(kZapValue), RelocInfo::NONE64);
- movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE64);
+ movq(address, kZapValue, RelocInfo::NONE64);
+ movq(value, kZapValue, RelocInfo::NONE64);
}
}
@@ -534,10 +535,9 @@
#endif
push(rax);
- movq(kScratchRegister, p0, RelocInfo::NONE64);
+ movq(kScratchRegister, reinterpret_cast<Smi*>(p0), RelocInfo::NONE64);
push(kScratchRegister);
- movq(kScratchRegister,
- reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(p1 - p0))),
+ movq(kScratchRegister, Smi::FromInt(static_cast<int>(p1 - p0)),
RelocInfo::NONE64);
push(kScratchRegister);
@@ -710,7 +710,7 @@
Register prev_next_address_reg = r14;
Register prev_limit_reg = rbx;
Register base_reg = r15;
- movq(base_reg, next_address);
+ Move(base_reg, next_address);
movq(prev_next_address_reg, Operand(base_reg, kNextOffset));
movq(prev_limit_reg, Operand(base_reg, kLimitOffset));
addl(Operand(base_reg, kLevelOffset), Immediate(1));
@@ -771,7 +771,7 @@
bind(&leave_exit_frame);
// Check if the function scheduled an exception.
- movq(rsi, scheduled_exception_address);
+ Move(rsi, scheduled_exception_address);
Cmp(Operand(rsi, 0), factory->the_hole_value());
j(not_equal, &promote_scheduled_exception);
bind(&exception_handled);
@@ -980,7 +980,7 @@
} else if (is_int32(x)) {
movq(dst, Immediate(static_cast<int32_t>(x)));
} else {
- movq(dst, x, RelocInfo::NONE64);
+ movq(dst, x);
}
}
@@ -1045,9 +1045,7 @@
void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) {
if (emit_debug_code()) {
- movq(dst,
- reinterpret_cast<uint64_t>(Smi::FromInt(kSmiConstantRegisterValue)),
- RelocInfo::NONE64);
+ movq(dst, Smi::FromInt(kSmiConstantRegisterValue), RelocInfo::NONE64);
cmpq(dst, kSmiConstantRegister);
if (allow_stub_calls()) {
Assert(equal, kUninitializedKSmiConstantRegister);
@@ -1094,7 +1092,7 @@
UNREACHABLE();
return;
default:
- movq(dst, reinterpret_cast<uint64_t>(source), RelocInfo::NONE64);
+ movq(dst, source, RelocInfo::NONE64);
return;
}
if (negative) {
@@ -1518,7 +1516,8 @@
void MacroAssembler::SmiAddConstant(Register dst,
Register src,
Smi* constant,
- Label* on_not_smi_result,
+ SmiOperationExecutionMode mode,
+ Label* bailout_label,
Label::Distance near_jump) {
if (constant->value() == 0) {
if (!dst.is(src)) {
@@ -1526,19 +1525,32 @@
}
} else if (dst.is(src)) {
ASSERT(!dst.is(kScratchRegister));
-
- Label done;
LoadSmiConstant(kScratchRegister, constant);
addq(dst, kScratchRegister);
- j(no_overflow, &done, Label::kNear);
- // Restore src.
- subq(dst, kScratchRegister);
- jmp(on_not_smi_result, near_jump);
- bind(&done);
+ if (mode.Contains(BAILOUT_ON_NO_OVERFLOW)) {
+ j(no_overflow, bailout_label, near_jump);
+ ASSERT(mode.Contains(PRESERVE_SOURCE_REGISTER));
+ subq(dst, kScratchRegister);
+ } else if (mode.Contains(BAILOUT_ON_OVERFLOW)) {
+ if (mode.Contains(PRESERVE_SOURCE_REGISTER)) {
+ Label done;
+ j(no_overflow, &done, Label::kNear);
+ subq(dst, kScratchRegister);
+ jmp(bailout_label, near_jump);
+ bind(&done);
+ } else {
+ // Bailout if overflow without reserving src.
+ j(overflow, bailout_label, near_jump);
+ }
+ } else {
+ CHECK(mode.IsEmpty());
+ }
} else {
+ ASSERT(mode.Contains(PRESERVE_SOURCE_REGISTER));
+ ASSERT(mode.Contains(BAILOUT_ON_OVERFLOW));
LoadSmiConstant(dst, constant);
addq(dst, src);
- j(overflow, on_not_smi_result, near_jump);
+ j(overflow, bailout_label, near_jump);
}
}
@@ -1570,7 +1582,8 @@
void MacroAssembler::SmiSubConstant(Register dst,
Register src,
Smi* constant,
- Label* on_not_smi_result,
+ SmiOperationExecutionMode mode,
+ Label* bailout_label,
Label::Distance near_jump) {
if (constant->value() == 0) {
if (!dst.is(src)) {
@@ -1578,35 +1591,40 @@
}
} else if (dst.is(src)) {
ASSERT(!dst.is(kScratchRegister));
- if (constant->value() == Smi::kMinValue) {
- // Subtracting min-value from any non-negative value will overflow.
- // We test the non-negativeness before doing the subtraction.
- testq(src, src);
- j(not_sign, on_not_smi_result, near_jump);
- LoadSmiConstant(kScratchRegister, constant);
- subq(dst, kScratchRegister);
+ LoadSmiConstant(kScratchRegister, constant);
+ subq(dst, kScratchRegister);
+ if (mode.Contains(BAILOUT_ON_NO_OVERFLOW)) {
+ j(no_overflow, bailout_label, near_jump);
+ ASSERT(mode.Contains(PRESERVE_SOURCE_REGISTER));
+ addq(dst, kScratchRegister);
+ } else if (mode.Contains(BAILOUT_ON_OVERFLOW)) {
+ if (mode.Contains(PRESERVE_SOURCE_REGISTER)) {
+ Label done;
+ j(no_overflow, &done, Label::kNear);
+ addq(dst, kScratchRegister);
+ jmp(bailout_label, near_jump);
+ bind(&done);
+ } else {
+ // Bailout if overflow without reserving src.
+ j(overflow, bailout_label, near_jump);
+ }
} else {
- // Subtract by adding the negation.
- LoadSmiConstant(kScratchRegister, Smi::FromInt(-constant->value()));
- addq(kScratchRegister, dst);
- j(overflow, on_not_smi_result, near_jump);
- movq(dst, kScratchRegister);
+ CHECK(mode.IsEmpty());
}
} else {
+ ASSERT(mode.Contains(PRESERVE_SOURCE_REGISTER));
+ ASSERT(mode.Contains(BAILOUT_ON_OVERFLOW));
if (constant->value() == Smi::kMinValue) {
- // Subtracting min-value from any non-negative value will overflow.
- // We test the non-negativeness before doing the subtraction.
- testq(src, src);
- j(not_sign, on_not_smi_result, near_jump);
- LoadSmiConstant(dst, constant);
- // Adding and subtracting the min-value gives the same result, it only
- // differs on the overflow bit, which we don't check here.
- addq(dst, src);
+ ASSERT(!dst.is(kScratchRegister));
+ movq(dst, src);
+ LoadSmiConstant(kScratchRegister, constant);
+ subq(dst, kScratchRegister);
+ j(overflow, bailout_label, near_jump);
} else {
// Subtract by adding the negation.
LoadSmiConstant(dst, Smi::FromInt(-(constant->value())));
addq(dst, src);
- j(overflow, on_not_smi_result, near_jump);
+ j(overflow, bailout_label, near_jump);
}
}
}
@@ -3120,9 +3138,7 @@
XMMRegister input_reg) {
Label done;
cvttsd2siq(result_reg, input_reg);
- movq(kScratchRegister,
- V8_INT64_C(0x8000000000000000),
- RelocInfo::NONE64);
+ movq(kScratchRegister, V8_INT64_C(0x8000000000000000));
cmpq(result_reg, kScratchRegister);
j(not_equal, &done, Label::kNear);
@@ -3272,7 +3288,7 @@
void MacroAssembler::AssertZeroExtended(Register int32_register) {
if (emit_debug_code()) {
ASSERT(!int32_register.is(kScratchRegister));
- movq(kScratchRegister, 0x100000000l, RelocInfo::NONE64);
+ movq(kScratchRegister, V8_INT64_C(0x0000000100000000));
cmpq(kScratchRegister, int32_register);
Check(above_equal, k32BitValueInRegisterIsNotZeroExtended);
}
@@ -4927,7 +4943,7 @@
lea(scratch_reg, Operand(receiver_reg,
JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
- movq(kScratchRegister, new_space_start);
+ Move(kScratchRegister, new_space_start);
cmpq(scratch_reg, kScratchRegister);
j(less, no_memento_found);
cmpq(scratch_reg, ExternalOperand(new_space_allocation_top));
@@ -4969,6 +4985,32 @@
}
+void MacroAssembler::JumpIfDictionaryInPrototypeChain(
+ Register object,
+ Register scratch0,
+ Register scratch1,
+ Label* found) {
+ ASSERT(!(scratch0.is(kScratchRegister) && scratch1.is(kScratchRegister)));
+ ASSERT(!scratch1.is(scratch0));
+ Register current = scratch0;
+ Label loop_again;
+
+ movq(current, object);
+
+ // Loop based on the map going up the prototype chain.
+ bind(&loop_again);
+ movq(current, FieldOperand(current, HeapObject::kMapOffset));
+ movq(scratch1, FieldOperand(current, Map::kBitField2Offset));
+ and_(scratch1, Immediate(Map::kElementsKindMask));
+ shr(scratch1, Immediate(Map::kElementsKindShift));
+ cmpq(scratch1, Immediate(DICTIONARY_ELEMENTS));
+ j(equal, found);
+ movq(current, FieldOperand(current, Map::kPrototypeOffset));
+ CompareRoot(current, Heap::kNullValueRootIndex);
+ j(not_equal, &loop_again);
+}
+
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_X64
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 2437434..7e00d64 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -53,6 +53,22 @@
enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
+enum SmiOperationConstraint {
+ PRESERVE_SOURCE_REGISTER,
+ BAILOUT_ON_NO_OVERFLOW,
+ BAILOUT_ON_OVERFLOW,
+ NUMBER_OF_CONSTRAINTS
+};
+
+STATIC_ASSERT(NUMBER_OF_CONSTRAINTS <= 8);
+
+class SmiOperationExecutionMode : public EnumSet<SmiOperationConstraint, byte> {
+ public:
+ SmiOperationExecutionMode() : EnumSet<SmiOperationConstraint, byte>(0) { }
+ explicit SmiOperationExecutionMode(byte bits)
+ : EnumSet<SmiOperationConstraint, byte>(bits) { }
+};
+
bool AreAliased(Register r1, Register r2, Register r3, Register r4);
// Forward declaration.
@@ -319,7 +335,7 @@
void InitializeRootRegister() {
ExternalReference roots_array_start =
ExternalReference::roots_array_start(isolate());
- movq(kRootRegister, roots_array_start);
+ Move(kRootRegister, roots_array_start);
addq(kRootRegister, Immediate(kRootRegisterBias));
}
@@ -384,8 +400,7 @@
void SafePush(Smi* src);
void InitializeSmiConstantRegister() {
- movq(kSmiConstantRegister,
- reinterpret_cast<uint64_t>(Smi::FromInt(kSmiConstantRegisterValue)),
+ movq(kSmiConstantRegister, Smi::FromInt(kSmiConstantRegisterValue),
RelocInfo::NONE64);
}
@@ -548,7 +563,8 @@
void SmiAddConstant(Register dst,
Register src,
Smi* constant,
- Label* on_not_smi_result,
+ SmiOperationExecutionMode mode,
+ Label* bailout_label,
Label::Distance near_jump = Label::kFar);
// Subtract an integer constant from a tagged smi, giving a tagged smi as
@@ -561,7 +577,8 @@
void SmiSubConstant(Register dst,
Register src,
Smi* constant,
- Label* on_not_smi_result,
+ SmiOperationExecutionMode mode,
+ Label* bailout_label,
Label::Distance near_jump = Label::kFar);
// Negating a smi can give a negative zero or too large positive value.
@@ -831,6 +848,10 @@
void PopReturnAddressTo(Register dst) { pop(dst); }
void MoveDouble(Register dst, const Operand& src) { movq(dst, src); }
void MoveDouble(const Operand& dst, Register src) { movq(dst, src); }
+ void Move(Register dst, ExternalReference ext) {
+ movq(dst, reinterpret_cast<Address>(ext.address()),
+ RelocInfo::EXTERNAL_REFERENCE);
+ }
// Control Flow
void Jump(Address destination, RelocInfo::Mode rmode);
@@ -1412,6 +1433,10 @@
bind(&no_memento_found);
}
+ // Jumps to found label if a prototype map has dictionary elements.
+ void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
+ Register scratch1, Label* found);
+
private:
// Order general registers are pushed by Pushad.
// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index ca834e2..3e65a68 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -618,7 +618,7 @@
__ cmpl(current_character(), Immediate('z'));
BranchOrBacktrack(above, on_no_match);
}
- __ movq(rbx, ExternalReference::re_word_character_map());
+ __ Move(rbx, ExternalReference::re_word_character_map());
ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
__ testb(Operand(rbx, current_character(), times_1, 0),
current_character());
@@ -632,7 +632,7 @@
__ cmpl(current_character(), Immediate('z'));
__ j(above, &done);
}
- __ movq(rbx, ExternalReference::re_word_character_map());
+ __ Move(rbx, ExternalReference::re_word_character_map());
ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
__ testb(Operand(rbx, current_character(), times_1, 0),
current_character());
@@ -718,7 +718,7 @@
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(isolate());
__ movq(rcx, rsp);
- __ movq(kScratchRegister, stack_limit);
+ __ Move(kScratchRegister, stack_limit);
__ subq(rcx, Operand(kScratchRegister, 0));
// Handle it if the stack pointer is already below the stack limit.
__ j(below_equal, &stack_limit_hit);
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 28e2a89..499ccdf 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -473,7 +473,7 @@
} else {
__ Move(args.GetArgumentOperand(offset - FCA::kDataIndex), call_data);
}
- __ movq(kScratchRegister,
+ __ Move(kScratchRegister,
ExternalReference::isolate_address(masm->isolate()));
__ movq(args.GetArgumentOperand(offset - FCA::kIsolateIndex),
kScratchRegister);
@@ -2293,7 +2293,7 @@
Label already_round;
__ bind(&conversion_failure);
int64_t kTwoMantissaBits= V8_INT64_C(0x4330000000000000);
- __ movq(rbx, kTwoMantissaBits, RelocInfo::NONE64);
+ __ movq(rbx, kTwoMantissaBits);
__ movq(xmm1, rbx);
__ ucomisd(xmm0, xmm1);
__ j(above_equal, &already_round);
@@ -2314,7 +2314,7 @@
// Subtract 1 if the argument was less than the tentative result.
int64_t kOne = V8_INT64_C(0x3ff0000000000000);
- __ movq(rbx, kOne, RelocInfo::NONE64);
+ __ movq(rbx, kOne);
__ movq(xmm1, rbx);
__ andpd(xmm1, xmm2);
__ subsd(xmm0, xmm1);
@@ -2418,8 +2418,7 @@
Label negative_sign;
const int sign_mask_shift =
(HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
- __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift,
- RelocInfo::NONE64);
+ __ Set(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift);
__ testq(rbx, rdi);
__ j(not_zero, &negative_sign);
__ ret(2 * kPointerSize);
@@ -3037,10 +3036,7 @@
// TODO(verwaest): Directly store to rax. Currently we cannot do this, since
// rax is used as receiver(), which we would otherwise clobber before a
// potential miss.
-
- __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
- HandlerFrontendHeader(
- object, receiver(), Handle<JSObject>::cast(global), name, &miss);
+ HandlerFrontendHeader(object, receiver(), global, name, &miss);
// Get the value from the cell.
__ Move(rbx, cell);
@@ -3064,7 +3060,7 @@
__ ret(0);
// Return the generated code.
- return GetICCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), Code::NORMAL, name);
}
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc
index 9fd68e5..3cef716 100644
--- a/test/cctest/test-compiler.cc
+++ b/test/cctest/test-compiler.cc
@@ -92,7 +92,8 @@
Handle<String> internalized_name =
isolate->factory()->InternalizeUtf8String(name);
Handle<JSObject> global(isolate->context()->global_object());
- SetProperty(isolate, global, internalized_name, object, NONE, kNonStrictMode);
+ Runtime::SetObjectProperty(isolate, global, internalized_name, object, NONE,
+ kNonStrictMode);
}
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 1bd1dc3..0c8a02b 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -169,10 +169,10 @@
v8::Utils::OpenHandle(*context_->Global())));
Handle<v8::internal::String> debug_string =
factory->InternalizeOneByteString(STATIC_ASCII_VECTOR("debug"));
- SetProperty(isolate, global, debug_string,
- Handle<Object>(debug->debug_context()->global_proxy(), isolate),
- DONT_ENUM,
- ::v8::internal::kNonStrictMode);
+ v8::internal::Runtime::SetObjectProperty(isolate, global, debug_string,
+ Handle<Object>(debug->debug_context()->global_proxy(), isolate),
+ DONT_ENUM,
+ ::v8::internal::kNonStrictMode);
}
private:
diff --git a/test/cctest/test-macro-assembler-x64.cc b/test/cctest/test-macro-assembler-x64.cc
index 61914b5..8262ab6 100644
--- a/test/cctest/test-macro-assembler-x64.cc
+++ b/test/cctest/test-macro-assembler-x64.cc
@@ -35,50 +35,53 @@
#include "serialize.h"
#include "cctest.h"
-using v8::internal::Assembler;
-using v8::internal::CodeDesc;
-using v8::internal::Condition;
-using v8::internal::FUNCTION_CAST;
-using v8::internal::HandleScope;
-using v8::internal::Immediate;
-using v8::internal::Isolate;
-using v8::internal::Label;
-using v8::internal::MacroAssembler;
-using v8::internal::OS;
-using v8::internal::Operand;
-using v8::internal::RelocInfo;
-using v8::internal::Representation;
-using v8::internal::Smi;
-using v8::internal::SmiIndex;
-using v8::internal::byte;
-using v8::internal::carry;
-using v8::internal::greater;
-using v8::internal::greater_equal;
-using v8::internal::kIntSize;
-using v8::internal::kPointerSize;
-using v8::internal::kSmiTagMask;
-using v8::internal::kSmiValueSize;
-using v8::internal::less_equal;
-using v8::internal::negative;
-using v8::internal::not_carry;
-using v8::internal::not_equal;
-using v8::internal::not_zero;
-using v8::internal::positive;
-using v8::internal::r11;
-using v8::internal::r13;
-using v8::internal::r14;
-using v8::internal::r15;
-using v8::internal::r8;
-using v8::internal::r9;
-using v8::internal::rax;
-using v8::internal::rbp;
-using v8::internal::rbx;
-using v8::internal::rcx;
-using v8::internal::rdi;
-using v8::internal::rdx;
-using v8::internal::rsi;
-using v8::internal::rsp;
-using v8::internal::times_pointer_size;
+namespace i = v8::internal;
+using i::Address;
+using i::Assembler;
+using i::CodeDesc;
+using i::Condition;
+using i::FUNCTION_CAST;
+using i::HandleScope;
+using i::Immediate;
+using i::Isolate;
+using i::Label;
+using i::MacroAssembler;
+using i::OS;
+using i::Operand;
+using i::RelocInfo;
+using i::Representation;
+using i::Smi;
+using i::SmiIndex;
+using i::byte;
+using i::carry;
+using i::greater;
+using i::greater_equal;
+using i::kIntSize;
+using i::kPointerSize;
+using i::kSmiTagMask;
+using i::kSmiValueSize;
+using i::less_equal;
+using i::negative;
+using i::not_carry;
+using i::not_equal;
+using i::equal;
+using i::not_zero;
+using i::positive;
+using i::r11;
+using i::r13;
+using i::r14;
+using i::r15;
+using i::r8;
+using i::r9;
+using i::rax;
+using i::rbp;
+using i::rbx;
+using i::rcx;
+using i::rdi;
+using i::rdx;
+using i::rsi;
+using i::rsp;
+using i::times_pointer_size;
// Test the x64 assembler by compiling some simple functions into
// a buffer and executing them. These tests do not initialize the
@@ -96,8 +99,8 @@
static void EntryCode(MacroAssembler* masm) {
// Smi constant register is callee save.
- __ push(v8::internal::kSmiConstantRegister);
- __ push(v8::internal::kRootRegister);
+ __ push(i::kSmiConstantRegister);
+ __ push(i::kRootRegister);
__ InitializeSmiConstantRegister();
__ InitializeRootRegister();
}
@@ -106,11 +109,11 @@
static void ExitCode(MacroAssembler* masm) {
// Return -1 if kSmiConstantRegister was clobbered during the test.
__ Move(rdx, Smi::FromInt(1));
- __ cmpq(rdx, v8::internal::kSmiConstantRegister);
+ __ cmpq(rdx, i::kSmiConstantRegister);
__ movq(rdx, Immediate(-1));
__ cmovq(not_equal, rax, rdx);
- __ pop(v8::internal::kRootRegister);
- __ pop(v8::internal::kSmiConstantRegister);
+ __ pop(i::kRootRegister);
+ __ pop(i::kSmiConstantRegister);
}
@@ -151,7 +154,7 @@
// Test that we can move a Smi value literally into a register.
TEST(SmiMove) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -239,7 +242,7 @@
// Test that we can compare smis for equality (and more).
TEST(SmiCompare) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -291,7 +294,7 @@
TEST(Integer32ToSmi) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -402,7 +405,7 @@
ASSERT(Smi::IsValid(result));
__ movl(rax, Immediate(id));
__ Move(r8, Smi::FromInt(static_cast<int>(result)));
- __ movq(rcx, x, RelocInfo::NONE64);
+ __ movq(rcx, x);
__ movq(r11, rcx);
__ Integer64PlusConstantToSmi(rdx, rcx, y);
__ cmpq(rdx, r8);
@@ -420,7 +423,7 @@
TEST(Integer64PlusConstantToSmi) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -465,7 +468,7 @@
TEST(SmiCheck) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -713,7 +716,7 @@
TEST(SmiNeg) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -770,7 +773,7 @@
__ j(not_equal, exit);
__ incq(rax);
- __ SmiAdd(rcx, rcx, rdx, exit); \
+ __ SmiAdd(rcx, rcx, rdx, exit);
__ cmpq(rcx, r8);
__ j(not_equal, exit);
@@ -789,13 +792,30 @@
__ movl(rcx, Immediate(first));
__ Integer32ToSmi(rcx, rcx);
+ i::SmiOperationExecutionMode mode;
+ mode.Add(i::PRESERVE_SOURCE_REGISTER);
+ mode.Add(i::BAILOUT_ON_OVERFLOW);
__ incq(rax);
- __ SmiAddConstant(r9, rcx, Smi::FromInt(second), exit);
+ __ SmiAddConstant(r9, rcx, Smi::FromInt(second), mode, exit);
__ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), exit);
+ __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), mode, exit);
+ __ cmpq(rcx, r8);
+ __ j(not_equal, exit);
+
+ __ movl(rcx, Immediate(first));
+ __ Integer32ToSmi(rcx, rcx);
+
+ mode.RemoveAll();
+ mode.Add(i::PRESERVE_SOURCE_REGISTER);
+ mode.Add(i::BAILOUT_ON_NO_OVERFLOW);
+ Label done;
+ __ incq(rax);
+ __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), mode, &done);
+ __ jmp(exit);
+ __ bind(&done);
__ cmpq(rcx, r8);
__ j(not_equal, exit);
}
@@ -835,11 +855,14 @@
__ j(not_equal, exit);
}
+ i::SmiOperationExecutionMode mode;
+ mode.Add(i::PRESERVE_SOURCE_REGISTER);
+ mode.Add(i::BAILOUT_ON_OVERFLOW);
__ movq(rcx, r11);
{
Label overflow_ok;
__ incq(rax);
- __ SmiAddConstant(r9, rcx, Smi::FromInt(y_min), &overflow_ok);
+ __ SmiAddConstant(r9, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
@@ -850,7 +873,7 @@
{
Label overflow_ok;
__ incq(rax);
- __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_min), &overflow_ok);
+ __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
@@ -886,7 +909,7 @@
{
Label overflow_ok;
__ incq(rax);
- __ SmiAddConstant(r9, rcx, Smi::FromInt(y_max), &overflow_ok);
+ __ SmiAddConstant(r9, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
@@ -894,21 +917,23 @@
__ j(not_equal, exit);
}
+ mode.RemoveAll();
+ mode.Add(i::BAILOUT_ON_OVERFLOW);
{
Label overflow_ok;
__ incq(rax);
- __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_max), &overflow_ok);
+ __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
__ cmpq(rcx, r11);
- __ j(not_equal, exit);
+ __ j(equal, exit);
}
}
TEST(SmiAdd) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -987,15 +1012,30 @@
__ cmpq(rcx, r8);
__ j(not_equal, exit);
+ i::SmiOperationExecutionMode mode;
+ mode.Add(i::PRESERVE_SOURCE_REGISTER);
+ mode.Add(i::BAILOUT_ON_OVERFLOW);
__ Move(rcx, Smi::FromInt(first));
-
__ incq(rax); // Test 4.
- __ SmiSubConstant(r9, rcx, Smi::FromInt(second), exit);
+ __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), mode, exit);
+ __ cmpq(rcx, r8);
+ __ j(not_equal, exit);
+
+ __ Move(rcx, Smi::FromInt(first));
+ __ incq(rax); // Test 5.
+ __ SmiSubConstant(r9, rcx, Smi::FromInt(second), mode, exit);
__ cmpq(r9, r8);
__ j(not_equal, exit);
- __ incq(rax); // Test 5.
- __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), exit);
+ mode.RemoveAll();
+ mode.Add(i::PRESERVE_SOURCE_REGISTER);
+ mode.Add(i::BAILOUT_ON_NO_OVERFLOW);
+ __ Move(rcx, Smi::FromInt(first));
+ Label done;
+ __ incq(rax); // Test 6.
+ __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), mode, &done);
+ __ jmp(exit);
+ __ bind(&done);
__ cmpq(rcx, r8);
__ j(not_equal, exit);
}
@@ -1035,11 +1075,15 @@
__ j(not_equal, exit);
}
+ i::SmiOperationExecutionMode mode;
+ mode.Add(i::PRESERVE_SOURCE_REGISTER);
+ mode.Add(i::BAILOUT_ON_OVERFLOW);
+
__ movq(rcx, r11);
{
Label overflow_ok;
__ incq(rax);
- __ SmiSubConstant(r9, rcx, Smi::FromInt(y_min), &overflow_ok);
+ __ SmiSubConstant(r9, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
@@ -1050,7 +1094,7 @@
{
Label overflow_ok;
__ incq(rax);
- __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_min), &overflow_ok);
+ __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
@@ -1086,7 +1130,7 @@
{
Label overflow_ok;
__ incq(rax);
- __ SmiSubConstant(r9, rcx, Smi::FromInt(y_max), &overflow_ok);
+ __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
@@ -1094,21 +1138,24 @@
__ j(not_equal, exit);
}
+ mode.RemoveAll();
+ mode.Add(i::BAILOUT_ON_OVERFLOW);
+ __ movq(rcx, r11);
{
Label overflow_ok;
__ incq(rax);
- __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), &overflow_ok);
+ __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
__ cmpq(rcx, r11);
- __ j(not_equal, exit);
+ __ j(equal, exit);
}
}
TEST(SmiSub) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1200,7 +1247,7 @@
TEST(SmiMul) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -1306,7 +1353,7 @@
TEST(SmiDiv) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1417,7 +1464,7 @@
TEST(SmiMod) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1515,7 +1562,7 @@
TEST(SmiIndex) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1585,7 +1632,7 @@
TEST(SmiSelectNonSmi) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1665,7 +1712,7 @@
TEST(SmiAnd) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1747,7 +1794,7 @@
TEST(SmiOr) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1831,7 +1878,7 @@
TEST(SmiXor) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1899,7 +1946,7 @@
TEST(SmiNot) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1996,7 +2043,7 @@
TEST(SmiShiftLeft) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -2103,7 +2150,7 @@
TEST(SmiShiftLogicalRight) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -2173,7 +2220,7 @@
TEST(SmiShiftArithmeticRight) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -2238,7 +2285,7 @@
TEST(PositiveSmiTimesPowerOfTwoToInteger64) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -2279,7 +2326,7 @@
TEST(OperandOffset) {
- v8::internal::V8::Initialize(NULL);
+ i::V8::Initialize(NULL);
int data[256];
for (int i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
@@ -2322,7 +2369,7 @@
__ lea(r13, Operand(rbp, -3 * kPointerSize));
__ lea(rbx, Operand(rbp, -5 * kPointerSize));
__ movl(rcx, Immediate(2));
- __ movq(r8, reinterpret_cast<uintptr_t>(&data[128]), RelocInfo::NONE64);
+ __ movq(r8, reinterpret_cast<Address>(&data[128]), RelocInfo::NONE64);
__ movl(rax, Immediate(1));
Operand sp0 = Operand(rsp, 0);
diff --git a/test/cctest/test-object-observe.cc b/test/cctest/test-object-observe.cc
index b4488a6..129e9d0 100644
--- a/test/cctest/test-object-observe.cc
+++ b/test/cctest/test-object-observe.cc
@@ -356,17 +356,17 @@
CompileRun("void 0");
CHECK_EQ(9, CompileRun("records.length")->Int32Value());
const RecordExpectation expected_records[] = {
- { obj, "new", "foo", Handle<Value>() },
- { obj, "new", "1", Handle<Value>() },
+ { obj, "add", "foo", Handle<Value>() },
+ { obj, "add", "1", Handle<Value>() },
// Note: use 7 not 1 below, as the latter triggers a nifty VS10 compiler bug
// where instead of 1.0, a garbage value would be passed into Number::New.
- { obj, "updated", "foo", Number::New(7) },
- { obj, "updated", "1", Number::New(2) },
- { obj, "updated", "1", Number::New(4) },
- { obj, "new", "1.1", Handle<Value>() },
- { obj, "deleted", "foo", Number::New(3) },
- { obj, "deleted", "1", Number::New(5) },
- { obj, "deleted", "1.1", Number::New(6) }
+ { obj, "update", "foo", Number::New(7) },
+ { obj, "update", "1", Number::New(2) },
+ { obj, "update", "1", Number::New(4) },
+ { obj, "add", "1.1", Handle<Value>() },
+ { obj, "delete", "foo", Number::New(3) },
+ { obj, "delete", "1", Number::New(5) },
+ { obj, "delete", "1.1", Number::New(6) }
};
EXPECT_RECORDS(CompileRun("records"), expected_records);
}
@@ -391,13 +391,13 @@
"obj.foo = 41;" // triggers a notification
"proto.foo = 42;"); // does not trigger a notification
const RecordExpectation expected_records[] = {
- { obj, "updated", "foo", Number::New(75) }
+ { obj, "update", "foo", Number::New(75) }
};
EXPECT_RECORDS(CompileRun("records"), expected_records);
obj->SetPrototype(Null(isolate.GetIsolate()));
CompileRun("obj.foo = 43");
const RecordExpectation expected_records2[] = {
- { obj, "new", "foo", Handle<Value>() }
+ { obj, "add", "foo", Handle<Value>() }
};
EXPECT_RECORDS(CompileRun("records"), expected_records2);
obj->SetPrototype(proto);
@@ -407,10 +407,10 @@
"Object.unobserve(obj, observer);"
"obj.foo = 44;");
const RecordExpectation expected_records3[] = {
- { proto, "new", "bar", Handle<Value>() }
+ { proto, "add", "bar", Handle<Value>() }
// TODO(adamk): The below record should be emitted since proto is observed
// and has been modified. Not clear if this happens in practice.
- // { proto, "updated", "foo", Number::New(43) }
+ // { proto, "update", "foo", Number::New(43) }
};
EXPECT_RECORDS(CompileRun("records"), expected_records3);
}
@@ -548,17 +548,17 @@
"obj.bar = 'baz';"
"objNoCheck.baz = 'quux'");
const RecordExpectation expected_records2[] = {
- { instance, "new", "foo", Handle<Value>() },
- { instance, "updated", "foo", String::New("bar") },
- { instance, "reconfigured", "foo", Number::New(5) },
- { instance, "new", "bar", Handle<Value>() },
- { obj_no_check, "new", "baz", Handle<Value>() },
+ { instance, "add", "foo", Handle<Value>() },
+ { instance, "update", "foo", String::New("bar") },
+ { instance, "reconfigure", "foo", Number::New(5) },
+ { instance, "add", "bar", Handle<Value>() },
+ { obj_no_check, "add", "baz", Handle<Value>() },
};
EXPECT_RECORDS(CompileRun("records2"), expected_records2);
}
const RecordExpectation expected_records[] = {
- { instance, "new", "bar", Handle<Value>() },
- { obj_no_check, "new", "baz", Handle<Value>() }
+ { instance, "add", "bar", Handle<Value>() },
+ { obj_no_check, "add", "baz", Handle<Value>() }
};
EXPECT_RECORDS(CompileRun("records"), expected_records);
}
@@ -595,17 +595,17 @@
"obj[8] = 'bar';"
"objNoCheck[42] = 'quux'");
const RecordExpectation expected_records2[] = {
- { instance, "new", "7", Handle<Value>() },
- { instance, "updated", "7", String::New("foo") },
- { instance, "reconfigured", "7", Number::New(5) },
- { instance, "new", "8", Handle<Value>() },
- { obj_no_check, "new", "42", Handle<Value>() }
+ { instance, "add", "7", Handle<Value>() },
+ { instance, "update", "7", String::New("foo") },
+ { instance, "reconfigure", "7", Number::New(5) },
+ { instance, "add", "8", Handle<Value>() },
+ { obj_no_check, "add", "42", Handle<Value>() }
};
EXPECT_RECORDS(CompileRun("records2"), expected_records2);
}
const RecordExpectation expected_records[] = {
- { instance, "new", "8", Handle<Value>() },
- { obj_no_check, "new", "42", Handle<Value>() }
+ { instance, "add", "8", Handle<Value>() },
+ { obj_no_check, "add", "42", Handle<Value>() }
};
EXPECT_RECORDS(CompileRun("records"), expected_records);
}
@@ -681,14 +681,14 @@
"obj[5] = 'baz';"
"objNoCheck.baz = 'quux'");
const RecordExpectation expected_records2[] = {
- { instance, "new", "foo", Handle<Value>() },
- { instance, "new", "5", Handle<Value>() },
- { obj_no_check, "new", "baz", Handle<Value>() },
+ { instance, "add", "foo", Handle<Value>() },
+ { instance, "add", "5", Handle<Value>() },
+ { obj_no_check, "add", "baz", Handle<Value>() },
};
EXPECT_RECORDS(CompileRun("records2"), expected_records2);
}
const RecordExpectation expected_records[] = {
- { obj_no_check, "new", "baz", Handle<Value>() }
+ { obj_no_check, "add", "baz", Handle<Value>() }
};
EXPECT_RECORDS(CompileRun("records"), expected_records);
}
@@ -713,8 +713,8 @@
instance->Set(String::New("foo"), String::New("bar"));
CompileRun(""); // trigger delivery
const RecordExpectation expected_records2[] = {
- { instance, "new", "5", Handle<Value>() },
- { instance, "new", "foo", Handle<Value>() }
+ { instance, "add", "5", Handle<Value>() },
+ { instance, "add", "foo", Handle<Value>() }
};
EXPECT_RECORDS(CompileRun("records2"), expected_records2);
}
diff --git a/test/mjsunit/allocation-site-info.js b/test/mjsunit/allocation-site-info.js
index f32344a..626696b 100644
--- a/test/mjsunit/allocation-site-info.js
+++ b/test/mjsunit/allocation-site-info.js
@@ -148,8 +148,12 @@
assertKind(elements_kind.fast_double, obj);
obj = fastliteralcase([3, 6, 2], 1.5);
assertKind(elements_kind.fast_double, obj);
+
+ // Note: thanks to pessimistic transition store stubs, we'll attempt
+ // to transition to the most general elements kind seen at a particular
+ // store site. So, the elements kind will be double.
obj = fastliteralcase([2, 6, 3], 2);
- assertKind(elements_kind.fast_smi_only, obj);
+ assertKind(elements_kind.fast_double, obj);
}
// Verify that we will not pretransition the double->fast path.
diff --git a/test/mjsunit/array-literal-feedback.js b/test/mjsunit/array-literal-feedback.js
index d2245c6..93ed3bc 100644
--- a/test/mjsunit/array-literal-feedback.js
+++ b/test/mjsunit/array-literal-feedback.js
@@ -35,6 +35,11 @@
// in this test case. Depending on whether smi-only arrays are actually
// enabled, this test takes the appropriate code path to check smi-only arrays.
+// Reset the GC stress mode to be off. Needed because AllocationMementos only
+// live for one gc, so a gc that happens in certain fragile areas of the test
+// can break assumptions.
+%SetFlags("--gc-interval=-1")
+
// support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6,7,8));
support_smi_only_arrays = true;
diff --git a/test/mjsunit/fast-prototype.js b/test/mjsunit/fast-prototype.js
index d700c3c..a86b0ea 100644
--- a/test/mjsunit/fast-prototype.js
+++ b/test/mjsunit/fast-prototype.js
@@ -29,6 +29,8 @@
// TODO(mstarzinger): This test does not succeed when GCs happen in
// between prototype transitions, we disable GC stress for now.
+%SetFlags("--gc-interval=-1")
+
// Flags: --noincremental-marking
// Check that objects that are used for prototypes are in the fast mode.
diff --git a/test/mjsunit/getters-on-elements.js b/test/mjsunit/getters-on-elements.js
new file mode 100644
index 0000000..55fc86b
--- /dev/null
+++ b/test/mjsunit/getters-on-elements.js
@@ -0,0 +1,214 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --max-opt-count=100 --noalways-opt
+
+// We specify max-opt-count because we opt/deopt the same function many
+// times.
+
+// It's nice to run this in other browsers too.
+var standalone = false;
+if (standalone) {
+ assertTrue = function(val) {
+ if (val != true) {
+ print("FAILURE");
+ }
+ }
+
+ assertFalse = function(val) {
+ if (val != false) {
+ print("FAILURE");
+ }
+ }
+
+ assertEquals = function(expected, val) {
+ if (expected !== val) {
+ print("FAILURE");
+ }
+ }
+
+ empty_func = function(name) { }
+ assertUnoptimized = empty_func;
+ assertOptimized = empty_func;
+
+ optimize = empty_func;
+ clearFunctionTypeFeedback = empty_func;
+ deoptimizeFunction = empty_func;
+} else {
+ optimize = function(name) {
+ %OptimizeFunctionOnNextCall(name);
+ }
+ clearFunctionTypeFeedback = function(name) {
+ %ClearFunctionTypeFeedback(name);
+ }
+ deoptimizeFunction = function(name) {
+ %DeoptimizeFunction(name);
+ }
+}
+
+function base_getter_test(create_func) {
+ var calls = 0;
+
+ // Testcase: setter in prototype chain
+ foo = function(a) { var x = a[0]; return x + 3; }
+ var a = create_func();
+ var ap = [];
+ ap.__defineGetter__(0, function() { calls++; return 0; });
+
+ foo(a);
+ foo(a);
+ foo(a);
+ delete a[0];
+
+ assertEquals(0, calls);
+ a.__proto__ = ap;
+ foo(a);
+ assertEquals(1, calls);
+ optimize(foo);
+ foo(a);
+ assertEquals(2, calls);
+ assertOptimized(foo);
+
+ // Testcase: getter "deep" in prototype chain.
+ clearFunctionTypeFeedback(foo);
+ deoptimizeFunction(foo);
+ clearFunctionTypeFeedback(foo);
+ calls = 0;
+
+ a = create_func();
+ var ap2 = [];
+ a.__proto__ = ap2;
+ foo(a);
+ foo(a);
+ foo(a);
+ delete a[0];
+
+ assertEquals(0, calls);
+
+ ap2.__proto__ = ap; // "sneak" in a callback.
+ // The sneak case should be caught by unoptimized code too.
+ assertUnoptimized(foo);
+ foo(a);
+ foo(a);
+ foo(a);
+ assertEquals(3, calls);
+
+ // Testcase: getter added after optimization (feedback is monomorphic)
+ clearFunctionTypeFeedback(foo);
+ deoptimizeFunction(foo);
+ clearFunctionTypeFeedback(foo);
+ calls = 0;
+
+ a = create_func();
+ ap2 = [];
+ a.__proto__ = ap2;
+ foo(a);
+ foo(a);
+ foo(a);
+ optimize(foo);
+ foo(a);
+ assertOptimized(foo);
+ delete a[0];
+ ap2.__proto__ = ap;
+ foo(a);
+ assertOptimized(foo); // getters don't require deopt on shape change.
+ assertEquals(1, calls);
+
+ // Testcase: adding additional getters to a prototype chain that already has
+ // one shouldn't deopt anything.
+ clearFunctionTypeFeedback(foo);
+ calls = 0;
+
+ a = create_func();
+ a.__proto__ = ap2;
+ bar = function(a) { return a[3] + 600; }
+ bar(a);
+ bar(a);
+ bar(a);
+ optimize(bar);
+ bar(a);
+ assertOptimized(bar);
+ assertEquals(0, calls);
+ delete a[3];
+ ap2.__defineGetter__(3, function() { calls++; return 0; });
+ bar(a);
+ assertOptimized(bar);
+ assertEquals(1, calls);
+}
+
+// Verify that map transitions don't confuse us.
+create_func_smi = function() { return [,,,,,,5]; }
+create_func_double = function() { return [,,,,,,5.5]; }
+create_func_fast = function() { return [,,,,,,true]; }
+
+var cf = [create_func_smi,
+ create_func_double,
+ create_func_fast];
+
+for(var c = 0; c < 3; c++) {
+ base_getter_test(cf[c]);
+}
+
+// A special test for LoadKeyedHoleMode. Ensure that optimized is generated
+// which sets ALLOW_RETURN_HOLE, then add a setter on the prototype that should
+// cause the function to deoptimize.
+
+var a = [3.5,,,3.5];
+fun = function(a) { return a[0] + 5.5; }
+fun(a);
+fun(a);
+fun(a); // should have a monomorphic KeyedLoadIC.
+optimize(fun);
+fun(a);
+assertOptimized(fun);
+
+// returning undefined shouldn't phase us.
+delete a[0];
+fun(a);
+assertOptimized(fun);
+
+// but messing up the prototype chain will.
+a.__proto__ = [];
+fun(a);
+assertUnoptimized(fun);
+
+// Construct a non-trivial prototype chain.
+var a = [3.5,,,,3.5];
+var ap = [,,3.5];
+ap.__proto__ = a.__proto__;
+a.__proto__ = ap;
+fun(a);
+optimize(fun);
+fun(a);
+assertOptimized(fun);
+
+var calls = 0;
+delete a[0];
+ap.__defineGetter__(0, function() { calls++; return 0; });
+fun(a);
+assertEquals(1, calls);
+assertUnoptimized(fun);
diff --git a/test/mjsunit/harmony/object-observe.js b/test/mjsunit/harmony/object-observe.js
index fa123e3..39bf6a5 100644
--- a/test/mjsunit/harmony/object-observe.js
+++ b/test/mjsunit/harmony/object-observe.js
@@ -187,21 +187,21 @@
// Multiple records are delivered.
reset();
notifier.notify({
- type: 'updated',
+ type: 'update',
name: 'foo',
expando: 1
});
notifier.notify({
object: notifier, // object property is ignored
- type: 'deleted',
+ type: 'delete',
name: 'bar',
expando2: 'str'
});
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, name: 'foo', type: 'updated', expando: 1 },
- { object: obj, name: 'bar', type: 'deleted', expando2: 'str' }
+ { object: obj, name: 'foo', type: 'update', expando: 1 },
+ { object: obj, name: 'bar', type: 'delete', expando2: 'str' }
]);
// Non-string accept values are coerced to strings
@@ -235,7 +235,7 @@
Object.observe(obj, observer.callback);
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
});
Object.deliverChangeRecords(observer.callback);
observer.assertCalled();
@@ -245,7 +245,7 @@
reset();
Object.unobserve(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
});
Object.deliverChangeRecords(observer.callback);
observer.assertNotCalled();
@@ -256,7 +256,7 @@
Object.unobserve(obj, observer.callback);
Object.unobserve(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
});
Object.deliverChangeRecords(observer.callback);
observer.assertNotCalled();
@@ -265,11 +265,11 @@
// Re-observation works and only includes changeRecords after of call.
reset();
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
});
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
});
records = undefined;
Object.deliverChangeRecords(observer.callback);
@@ -283,7 +283,7 @@
obj.id = 1;
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'new', name: 'id' },
+ { object: obj, type: 'add', name: 'id' },
]);
// The empty-string property is observable
@@ -295,9 +295,9 @@
delete obj[''];
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'new', name: '' },
- { object: obj, type: 'updated', name: '', oldValue: '' },
- { object: obj, type: 'deleted', name: '', oldValue: ' ' },
+ { object: obj, type: 'add', name: '' },
+ { object: obj, type: 'update', name: '', oldValue: '' },
+ { object: obj, type: 'delete', name: '', oldValue: ' ' },
]);
// Object.preventExtensions
@@ -309,7 +309,7 @@
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'new', name: 'baz' },
+ { object: obj, type: 'add', name: 'baz' },
{ object: obj, type: 'preventExtensions' },
]);
@@ -344,9 +344,9 @@
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'reconfigured', name: 'a' },
- { object: obj, type: 'reconfigured', name: 'b' },
- { object: obj, type: 'reconfigured', name: 'c' },
+ { object: obj, type: 'reconfigure', name: 'a' },
+ { object: obj, type: 'reconfigure', name: 'b' },
+ { object: obj, type: 'reconfigure', name: 'c' },
{ object: obj, type: 'preventExtensions' },
]);
@@ -381,8 +381,8 @@
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'reconfigured', name: 'a' },
- { object: obj, type: 'reconfigured', name: 'b' },
+ { object: obj, type: 'reconfigure', name: 'a' },
+ { object: obj, type: 'reconfigure', name: 'b' },
{ object: obj, type: 'preventExtensions' },
]);
@@ -399,101 +399,101 @@
var obj = {};
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
val: 1
});
Object.unobserve(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
val: 2
});
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
val: 3
});
Object.unobserve(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
val: 4
});
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'updated',
+ type: 'update',
val: 5
});
Object.unobserve(obj, observer.callback);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'updated', val: 1 },
- { object: obj, type: 'updated', val: 3 },
- { object: obj, type: 'updated', val: 5 }
+ { object: obj, type: 'update', val: 1 },
+ { object: obj, type: 'update', val: 3 },
+ { object: obj, type: 'update', val: 5 }
]);
// Accept
reset();
Object.observe(obj, observer.callback, ['somethingElse']);
Object.getNotifier(obj).notify({
- type: 'new'
+ type: 'add'
});
Object.getNotifier(obj).notify({
- type: 'updated'
+ type: 'update'
});
Object.getNotifier(obj).notify({
- type: 'deleted'
+ type: 'delete'
});
Object.getNotifier(obj).notify({
- type: 'reconfigured'
+ type: 'reconfigure'
});
Object.getNotifier(obj).notify({
- type: 'prototype'
+ type: 'setPrototype'
});
Object.deliverChangeRecords(observer.callback);
observer.assertNotCalled();
reset();
-Object.observe(obj, observer.callback, ['new', 'deleted', 'prototype']);
+Object.observe(obj, observer.callback, ['add', 'delete', 'setPrototype']);
Object.getNotifier(obj).notify({
- type: 'new'
+ type: 'add'
});
Object.getNotifier(obj).notify({
- type: 'updated'
+ type: 'update'
});
Object.getNotifier(obj).notify({
- type: 'deleted'
+ type: 'delete'
});
Object.getNotifier(obj).notify({
- type: 'deleted'
+ type: 'delete'
});
Object.getNotifier(obj).notify({
- type: 'reconfigured'
+ type: 'reconfigure'
});
Object.getNotifier(obj).notify({
- type: 'prototype'
+ type: 'setPrototype'
});
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'new' },
- { object: obj, type: 'deleted' },
- { object: obj, type: 'deleted' },
- { object: obj, type: 'prototype' }
+ { object: obj, type: 'add' },
+ { object: obj, type: 'delete' },
+ { object: obj, type: 'delete' },
+ { object: obj, type: 'setPrototype' }
]);
reset();
-Object.observe(obj, observer.callback, ['updated', 'foo']);
+Object.observe(obj, observer.callback, ['update', 'foo']);
Object.getNotifier(obj).notify({
- type: 'new'
+ type: 'add'
});
Object.getNotifier(obj).notify({
- type: 'updated'
+ type: 'update'
});
Object.getNotifier(obj).notify({
- type: 'deleted'
+ type: 'delete'
});
Object.getNotifier(obj).notify({
type: 'foo'
@@ -506,7 +506,7 @@
});
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'updated' },
+ { object: obj, type: 'update' },
{ object: obj, type: 'foo' },
{ object: obj, type: 'foo' }
]);
@@ -570,7 +570,7 @@
Object.observe(thingy, callback, [Thingy.INCREMENT,
Thingy.MULTIPLY,
Thingy.INCREMENT_AND_MULTIPLY,
- 'updated']);
+ 'update']);
}
Thingy.unobserve = function(thingy, callback) {
@@ -590,22 +590,22 @@
Object.deliverChangeRecords(observer.callback);
Object.deliverChangeRecords(observer2.callback);
observer.assertCallbackRecords([
- { object: thingy, type: 'updated', name: 'a', oldValue: 2 },
- { object: thingy, type: 'updated', name: 'b', oldValue: 4 },
- { object: thingy, type: 'updated', name: 'b', oldValue: 7 },
- { object: thingy, type: 'updated', name: 'a', oldValue: 5 },
- { object: thingy, type: 'updated', name: 'b', oldValue: 8 },
- { object: thingy, type: 'updated', name: 'a', oldValue: 10 },
- { object: thingy, type: 'updated', name: 'a', oldValue: 11 },
- { object: thingy, type: 'updated', name: 'b', oldValue: 16 },
- { object: thingy, type: 'updated', name: 'a', oldValue: 13 },
- { object: thingy, type: 'updated', name: 'b', oldValue: 18 },
+ { object: thingy, type: 'update', name: 'a', oldValue: 2 },
+ { object: thingy, type: 'update', name: 'b', oldValue: 4 },
+ { object: thingy, type: 'update', name: 'b', oldValue: 7 },
+ { object: thingy, type: 'update', name: 'a', oldValue: 5 },
+ { object: thingy, type: 'update', name: 'b', oldValue: 8 },
+ { object: thingy, type: 'update', name: 'a', oldValue: 10 },
+ { object: thingy, type: 'update', name: 'a', oldValue: 11 },
+ { object: thingy, type: 'update', name: 'b', oldValue: 16 },
+ { object: thingy, type: 'update', name: 'a', oldValue: 13 },
+ { object: thingy, type: 'update', name: 'b', oldValue: 18 },
]);
observer2.assertCallbackRecords([
{ object: thingy, type: Thingy.INCREMENT, incremented: 3 },
- { object: thingy, type: 'updated', name: 'b', oldValue: 7 },
+ { object: thingy, type: 'update', name: 'b', oldValue: 7 },
{ object: thingy, type: Thingy.MULTIPLY, multiplied: 2 },
- { object: thingy, type: 'updated', name: 'a', oldValue: 10 },
+ { object: thingy, type: 'update', name: 'a', oldValue: 10 },
{
object: thingy,
type: Thingy.INCREMENT_AND_MULTIPLY,
@@ -659,9 +659,9 @@
Object.deliverChangeRecords(observer.callback);
Object.deliverChangeRecords(observer2.callback);
observer.assertCallbackRecords([
- { object: thingy, type: 'updated', name: '2', oldValue: 3 },
- { object: thingy, type: 'updated', name: '1', oldValue: 2 },
- { object: thingy, type: 'updated', name: '0', oldValue: 1 }
+ { object: thingy, type: 'update', name: '2', oldValue: 3 },
+ { object: thingy, type: 'update', name: '1', oldValue: 2 },
+ { object: thingy, type: 'update', name: '0', oldValue: 1 }
]);
observer2.assertCallbackRecords([
{ object: thingy, type: RecursiveThingy.MULTIPLY_FIRST_N, multiplied: 2, n: 3 }
@@ -725,20 +725,20 @@
Object.observe(obj3, observer.callback);
Object.observe(obj2, observer.callback);
Object.getNotifier(obj).notify({
- type: 'new',
+ type: 'add',
});
Object.getNotifier(obj2).notify({
- type: 'updated',
+ type: 'update',
});
Object.getNotifier(obj3).notify({
- type: 'deleted',
+ type: 'delete',
});
Object.observe(obj3, observer.callback);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'new' },
- { object: obj2, type: 'updated' },
- { object: obj3, type: 'deleted' }
+ { object: obj, type: 'add' },
+ { object: obj2, type: 'update' },
+ { object: obj3, type: 'delete' }
]);
@@ -805,28 +805,28 @@
Object.defineProperty(obj, "a", {value: 11, configurable: true});
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, name: "a", type: "updated", oldValue: 1 },
- { object: obj, name: "a", type: "updated", oldValue: 2 },
- { object: obj, name: "a", type: "deleted", oldValue: 3 },
- { object: obj, name: "a", type: "new" },
- { object: obj, name: "a", type: "updated", oldValue: 4 },
- { object: obj, name: "a", type: "updated", oldValue: 5 },
- { object: obj, name: "a", type: "reconfigured" },
- { object: obj, name: "a", type: "updated", oldValue: 6 },
- { object: obj, name: "a", type: "reconfigured", oldValue: 8 },
- { object: obj, name: "a", type: "reconfigured", oldValue: 7 },
- { object: obj, name: "a", type: "reconfigured" },
- { object: obj, name: "a", type: "reconfigured" },
- { object: obj, name: "a", type: "reconfigured" },
- { object: obj, name: "a", type: "deleted" },
- { object: obj, name: "a", type: "new" },
- { object: obj, name: "a", type: "reconfigured" },
- { object: obj, name: "a", type: "updated", oldValue: 9 },
- { object: obj, name: "a", type: "updated", oldValue: 10 },
- { object: obj, name: "a", type: "updated", oldValue: 11 },
- { object: obj, name: "a", type: "updated", oldValue: 12 },
- { object: obj, name: "a", type: "deleted", oldValue: 36 },
- { object: obj, name: "a", type: "new" },
+ { object: obj, name: "a", type: "update", oldValue: 1 },
+ { object: obj, name: "a", type: "update", oldValue: 2 },
+ { object: obj, name: "a", type: "delete", oldValue: 3 },
+ { object: obj, name: "a", type: "add" },
+ { object: obj, name: "a", type: "update", oldValue: 4 },
+ { object: obj, name: "a", type: "update", oldValue: 5 },
+ { object: obj, name: "a", type: "reconfigure" },
+ { object: obj, name: "a", type: "update", oldValue: 6 },
+ { object: obj, name: "a", type: "reconfigure", oldValue: 8 },
+ { object: obj, name: "a", type: "reconfigure", oldValue: 7 },
+ { object: obj, name: "a", type: "reconfigure" },
+ { object: obj, name: "a", type: "reconfigure" },
+ { object: obj, name: "a", type: "reconfigure" },
+ { object: obj, name: "a", type: "delete" },
+ { object: obj, name: "a", type: "add" },
+ { object: obj, name: "a", type: "reconfigure" },
+ { object: obj, name: "a", type: "update", oldValue: 9 },
+ { object: obj, name: "a", type: "update", oldValue: 10 },
+ { object: obj, name: "a", type: "update", oldValue: 11 },
+ { object: obj, name: "a", type: "update", oldValue: 12 },
+ { object: obj, name: "a", type: "delete", oldValue: 36 },
+ { object: obj, name: "a", type: "add" },
]);
@@ -863,28 +863,28 @@
Object.defineProperty(obj, "1", {value: 11, configurable: true});
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, name: "1", type: "updated", oldValue: 1 },
- { object: obj, name: "1", type: "updated", oldValue: 2 },
- { object: obj, name: "1", type: "deleted", oldValue: 3 },
- { object: obj, name: "1", type: "new" },
- { object: obj, name: "1", type: "updated", oldValue: 4 },
- { object: obj, name: "1", type: "updated", oldValue: 5 },
- { object: obj, name: "1", type: "reconfigured" },
- { object: obj, name: "1", type: "updated", oldValue: 6 },
- { object: obj, name: "1", type: "reconfigured", oldValue: 8 },
- { object: obj, name: "1", type: "reconfigured", oldValue: 7 },
- { object: obj, name: "1", type: "reconfigured" },
- { object: obj, name: "1", type: "reconfigured" },
- { object: obj, name: "1", type: "reconfigured" },
- { object: obj, name: "1", type: "deleted" },
- { object: obj, name: "1", type: "new" },
- { object: obj, name: "1", type: "reconfigured" },
- { object: obj, name: "1", type: "updated", oldValue: 9 },
- { object: obj, name: "1", type: "updated", oldValue: 10 },
- { object: obj, name: "1", type: "updated", oldValue: 11 },
- { object: obj, name: "1", type: "updated", oldValue: 12 },
- { object: obj, name: "1", type: "deleted", oldValue: 36 },
- { object: obj, name: "1", type: "new" },
+ { object: obj, name: "1", type: "update", oldValue: 1 },
+ { object: obj, name: "1", type: "update", oldValue: 2 },
+ { object: obj, name: "1", type: "delete", oldValue: 3 },
+ { object: obj, name: "1", type: "add" },
+ { object: obj, name: "1", type: "update", oldValue: 4 },
+ { object: obj, name: "1", type: "update", oldValue: 5 },
+ { object: obj, name: "1", type: "reconfigure" },
+ { object: obj, name: "1", type: "update", oldValue: 6 },
+ { object: obj, name: "1", type: "reconfigure", oldValue: 8 },
+ { object: obj, name: "1", type: "reconfigure", oldValue: 7 },
+ { object: obj, name: "1", type: "reconfigure" },
+ { object: obj, name: "1", type: "reconfigure" },
+ { object: obj, name: "1", type: "reconfigure" },
+ { object: obj, name: "1", type: "delete" },
+ { object: obj, name: "1", type: "add" },
+ { object: obj, name: "1", type: "reconfigure" },
+ { object: obj, name: "1", type: "update", oldValue: 9 },
+ { object: obj, name: "1", type: "update", oldValue: 10 },
+ { object: obj, name: "1", type: "update", oldValue: 11 },
+ { object: obj, name: "1", type: "update", oldValue: 12 },
+ { object: obj, name: "1", type: "delete", oldValue: 36 },
+ { object: obj, name: "1", type: "add" },
]);
@@ -952,32 +952,32 @@
Object.defineProperty(obj, prop, {value: 11, configurable: true});
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, name: prop, type: "updated", oldValue: 1 },
- { object: obj, name: prop, type: "updated", oldValue: 2 },
- { object: obj, name: prop, type: "deleted", oldValue: 3 },
- { object: obj, name: prop, type: "new" },
- { object: obj, name: prop, type: "updated", oldValue: 4 },
- { object: obj, name: prop, type: "updated", oldValue: 5 },
- { object: obj, name: prop, type: "reconfigured" },
- { object: obj, name: prop, type: "updated", oldValue: 6 },
- { object: obj, name: prop, type: "reconfigured", oldValue: 8 },
- { object: obj, name: prop, type: "reconfigured", oldValue: 7 },
- { object: obj, name: prop, type: "reconfigured" },
- { object: obj, name: prop, type: "reconfigured" },
- { object: obj, name: prop, type: "reconfigured" },
- { object: obj, name: prop, type: "reconfigured" },
- { object: obj, name: prop, type: "reconfigured" },
- { object: obj, name: prop, type: "deleted" },
- { object: obj, name: prop, type: "new" },
- { object: obj, name: prop, type: "deleted" },
- { object: obj, name: prop, type: "new" },
- { object: obj, name: prop, type: "reconfigured" },
- { object: obj, name: prop, type: "updated", oldValue: 9 },
- { object: obj, name: prop, type: "updated", oldValue: 10 },
- { object: obj, name: prop, type: "updated", oldValue: 11 },
- { object: obj, name: prop, type: "updated", oldValue: 12 },
- { object: obj, name: prop, type: "deleted", oldValue: 36 },
- { object: obj, name: prop, type: "new" },
+ { object: obj, name: prop, type: "update", oldValue: 1 },
+ { object: obj, name: prop, type: "update", oldValue: 2 },
+ { object: obj, name: prop, type: "delete", oldValue: 3 },
+ { object: obj, name: prop, type: "add" },
+ { object: obj, name: prop, type: "update", oldValue: 4 },
+ { object: obj, name: prop, type: "update", oldValue: 5 },
+ { object: obj, name: prop, type: "reconfigure" },
+ { object: obj, name: prop, type: "update", oldValue: 6 },
+ { object: obj, name: prop, type: "reconfigure", oldValue: 8 },
+ { object: obj, name: prop, type: "reconfigure", oldValue: 7 },
+ { object: obj, name: prop, type: "reconfigure" },
+ { object: obj, name: prop, type: "reconfigure" },
+ { object: obj, name: prop, type: "reconfigure" },
+ { object: obj, name: prop, type: "reconfigure" },
+ { object: obj, name: prop, type: "reconfigure" },
+ { object: obj, name: prop, type: "delete" },
+ { object: obj, name: prop, type: "add" },
+ { object: obj, name: prop, type: "delete" },
+ { object: obj, name: prop, type: "add" },
+ { object: obj, name: prop, type: "reconfigure" },
+ { object: obj, name: prop, type: "update", oldValue: 9 },
+ { object: obj, name: prop, type: "update", oldValue: 10 },
+ { object: obj, name: prop, type: "update", oldValue: 11 },
+ { object: obj, name: prop, type: "update", oldValue: 12 },
+ { object: obj, name: prop, type: "delete", oldValue: 36 },
+ { object: obj, name: prop, type: "add" },
]);
Object.unobserve(obj, observer.callback);
delete obj[prop];
@@ -1000,11 +1000,11 @@
obj[prop] = 7; // ignored
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, name: prop, type: "updated", oldValue: 1 },
- { object: obj, name: prop, type: "updated", oldValue: 4 },
- { object: obj, name: prop, type: "updated", oldValue: 5 },
- { object: obj, name: prop, type: "updated", oldValue: 6 },
- { object: obj, name: prop, type: "reconfigured" },
+ { object: obj, name: prop, type: "update", oldValue: 1 },
+ { object: obj, name: prop, type: "update", oldValue: 4 },
+ { object: obj, name: prop, type: "update", oldValue: 5 },
+ { object: obj, name: prop, type: "update", oldValue: 6 },
+ { object: obj, name: prop, type: "reconfigure" },
]);
Object.unobserve(obj, observer.callback);
}
@@ -1064,7 +1064,7 @@
createProxy(Proxy.create, null),
createProxy(Proxy.createFunction, function(){}),
];
-var properties = ["a", "1", 1, "length", "prototype", "name", "caller"];
+var properties = ["a", "1", 1, "length", "setPrototype", "name", "caller"];
// Cases that yield non-standard results.
function blacklisted(obj, prop) {
@@ -1118,31 +1118,31 @@
Object.defineProperty(arr3, 'length', {value: 1, writable: false});
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: arr, name: '3', type: 'deleted', oldValue: 'd' },
- { object: arr, name: '2', type: 'deleted' },
- { object: arr, name: 'length', type: 'updated', oldValue: 4 },
- { object: arr, name: '1', type: 'deleted', oldValue: 'b' },
- { object: arr, name: 'length', type: 'updated', oldValue: 2 },
- { object: arr, name: 'length', type: 'updated', oldValue: 1 },
- { object: arr, name: 'length', type: 'reconfigured' },
- { object: arr2, name: '1', type: 'deleted', oldValue: 'beta' },
- { object: arr2, name: 'length', type: 'updated', oldValue: 2 },
- { object: arr2, name: 'length', type: 'reconfigured' },
- { object: arr3, name: '2', type: 'deleted', oldValue: 'goodbye' },
- { object: arr3, name: '0', type: 'deleted', oldValue: 'hello' },
- { object: arr3, name: 'length', type: 'updated', oldValue: 6 },
- { object: arr3, name: 'length', type: 'updated', oldValue: 0 },
- { object: arr3, name: 'length', type: 'updated', oldValue: 1 },
- { object: arr3, name: 'length', type: 'updated', oldValue: 2 },
- { object: arr3, name: 'length', type: 'updated', oldValue: 1 },
- { object: arr3, name: '4', type: 'new' },
- { object: arr3, name: '4', type: 'deleted', oldValue: 5 },
+ { object: arr, name: '3', type: 'delete', oldValue: 'd' },
+ { object: arr, name: '2', type: 'delete' },
+ { object: arr, name: 'length', type: 'update', oldValue: 4 },
+ { object: arr, name: '1', type: 'delete', oldValue: 'b' },
+ { object: arr, name: 'length', type: 'update', oldValue: 2 },
+ { object: arr, name: 'length', type: 'update', oldValue: 1 },
+ { object: arr, name: 'length', type: 'reconfigure' },
+ { object: arr2, name: '1', type: 'delete', oldValue: 'beta' },
+ { object: arr2, name: 'length', type: 'update', oldValue: 2 },
+ { object: arr2, name: 'length', type: 'reconfigure' },
+ { object: arr3, name: '2', type: 'delete', oldValue: 'goodbye' },
+ { object: arr3, name: '0', type: 'delete', oldValue: 'hello' },
+ { object: arr3, name: 'length', type: 'update', oldValue: 6 },
+ { object: arr3, name: 'length', type: 'update', oldValue: 0 },
+ { object: arr3, name: 'length', type: 'update', oldValue: 1 },
+ { object: arr3, name: 'length', type: 'update', oldValue: 2 },
+ { object: arr3, name: 'length', type: 'update', oldValue: 1 },
+ { object: arr3, name: '4', type: 'add' },
+ { object: arr3, name: '4', type: 'delete', oldValue: 5 },
// TODO(rafaelw): It breaks spec compliance to get two records here.
// When the TODO in v8natives.js::DefineArrayProperty is addressed
// which prevents DefineProperty from over-writing the magic length
// property, these will collapse into a single record.
- { object: arr3, name: 'length', type: 'updated', oldValue: 5 },
- { object: arr3, name: 'length', type: 'reconfigured' }
+ { object: arr3, name: 'length', type: 'update', oldValue: 5 },
+ { object: arr3, name: 'length', type: 'reconfigure' }
]);
Object.deliverChangeRecords(observer2.callback);
observer2.assertCallbackRecords([
@@ -1155,7 +1155,7 @@
{ object: arr3, type: 'splice', index: 1, removed: [], addedCount: 1 },
{ object: arr3, type: 'splice', index: 1, removed: [,], addedCount: 0 },
{ object: arr3, type: 'splice', index: 1, removed: [], addedCount: 4 },
- { object: arr3, name: '4', type: 'new' },
+ { object: arr3, name: '4', type: 'add' },
{ object: arr3, type: 'splice', index: 1, removed: [,,,5], addedCount: 0 }
]);
@@ -1173,8 +1173,8 @@
slow_arr.length = 100;
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: slow_arr, name: '500000000', type: 'deleted', oldValue: 'hello' },
- { object: slow_arr, name: 'length', type: 'updated', oldValue: 1000000000 },
+ { object: slow_arr, name: '500000000', type: 'delete', oldValue: 'hello' },
+ { object: slow_arr, name: 'length', type: 'update', oldValue: 1000000000 },
]);
Object.deliverChangeRecords(slowSpliceCallback);
assertEquals(spliceRecords.length, 1);
@@ -1200,11 +1200,11 @@
}
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, name: "a0", type: "new" },
- { object: obj, name: "a1", type: "new" },
- { object: obj, name: "a2", type: "new" },
- { object: obj, name: "a3", type: "new" },
- { object: obj, name: "a4", type: "new" },
+ { object: obj, name: "a0", type: "add" },
+ { object: obj, name: "a1", type: "add" },
+ { object: obj, name: "a2", type: "add" },
+ { object: obj, name: "a3", type: "add" },
+ { object: obj, name: "a4", type: "add" },
]);
reset();
@@ -1215,11 +1215,11 @@
}
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, name: "0", type: "new" },
- { object: obj, name: "1", type: "new" },
- { object: obj, name: "2", type: "new" },
- { object: obj, name: "3", type: "new" },
- { object: obj, name: "4", type: "new" },
+ { object: obj, name: "0", type: "add" },
+ { object: obj, name: "1", type: "add" },
+ { object: obj, name: "2", type: "add" },
+ { object: obj, name: "3", type: "add" },
+ { object: obj, name: "4", type: "add" },
]);
@@ -1236,15 +1236,15 @@
arr[50] = 30; // no length change expected
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: arr, name: '3', type: 'new' },
- { object: arr, name: 'length', type: 'updated', oldValue: 3 },
- { object: arr, name: '100', type: 'new' },
- { object: arr, name: 'length', type: 'updated', oldValue: 4 },
- { object: arr, name: '200', type: 'new' },
- { object: arr, name: 'length', type: 'updated', oldValue: 101 },
- { object: arr, name: '400', type: 'new' },
- { object: arr, name: 'length', type: 'updated', oldValue: 201 },
- { object: arr, name: '50', type: 'new' },
+ { object: arr, name: '3', type: 'add' },
+ { object: arr, name: 'length', type: 'update', oldValue: 3 },
+ { object: arr, name: '100', type: 'add' },
+ { object: arr, name: 'length', type: 'update', oldValue: 4 },
+ { object: arr, name: '200', type: 'add' },
+ { object: arr, name: 'length', type: 'update', oldValue: 101 },
+ { object: arr, name: '400', type: 'add' },
+ { object: arr, name: 'length', type: 'update', oldValue: 201 },
+ { object: arr, name: '50', type: 'add' },
]);
Object.deliverChangeRecords(observer2.callback);
observer2.assertCallbackRecords([
@@ -1252,7 +1252,7 @@
{ object: arr, type: 'splice', index: 4, removed: [], addedCount: 97 },
{ object: arr, type: 'splice', index: 101, removed: [], addedCount: 100 },
{ object: arr, type: 'splice', index: 201, removed: [], addedCount: 200 },
- { object: arr, type: 'new', name: '50' },
+ { object: arr, type: 'add', name: '50' },
]);
@@ -1269,12 +1269,12 @@
array.push(5);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '2', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
- { object: array, name: '3', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 3 },
- { object: array, name: '4', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 4 },
+ { object: array, name: '2', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 2 },
+ { object: array, name: '3', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 3 },
+ { object: array, name: '4', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 4 },
]);
Object.deliverChangeRecords(observer2.callback);
observer2.assertCallbackRecords([
@@ -1290,10 +1290,10 @@
array.pop();
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '1', type: 'deleted', oldValue: 2 },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
- { object: array, name: '0', type: 'deleted', oldValue: 1 },
- { object: array, name: 'length', type: 'updated', oldValue: 1 },
+ { object: array, name: '1', type: 'delete', oldValue: 2 },
+ { object: array, name: 'length', type: 'update', oldValue: 2 },
+ { object: array, name: '0', type: 'delete', oldValue: 1 },
+ { object: array, name: 'length', type: 'update', oldValue: 1 },
]);
// Shift
@@ -1304,11 +1304,11 @@
array.shift();
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '0', type: 'updated', oldValue: 1 },
- { object: array, name: '1', type: 'deleted', oldValue: 2 },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
- { object: array, name: '0', type: 'deleted', oldValue: 2 },
- { object: array, name: 'length', type: 'updated', oldValue: 1 },
+ { object: array, name: '0', type: 'update', oldValue: 1 },
+ { object: array, name: '1', type: 'delete', oldValue: 2 },
+ { object: array, name: 'length', type: 'update', oldValue: 2 },
+ { object: array, name: '0', type: 'delete', oldValue: 2 },
+ { object: array, name: 'length', type: 'update', oldValue: 1 },
]);
// Unshift
@@ -1318,11 +1318,11 @@
array.unshift(3, 4);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '3', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
- { object: array, name: '2', type: 'new' },
- { object: array, name: '0', type: 'updated', oldValue: 1 },
- { object: array, name: '1', type: 'updated', oldValue: 2 },
+ { object: array, name: '3', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 2 },
+ { object: array, name: '2', type: 'add' },
+ { object: array, name: '0', type: 'update', oldValue: 1 },
+ { object: array, name: '1', type: 'update', oldValue: 2 },
]);
// Splice
@@ -1332,10 +1332,10 @@
array.splice(1, 1, 4, 5);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '3', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 3 },
- { object: array, name: '1', type: 'updated', oldValue: 2 },
- { object: array, name: '2', type: 'updated', oldValue: 3 },
+ { object: array, name: '3', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 3 },
+ { object: array, name: '1', type: 'update', oldValue: 2 },
+ { object: array, name: '2', type: 'update', oldValue: 3 },
]);
// Sort
@@ -1348,11 +1348,11 @@
assertEquals(3, array[2]);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '1', type: 'updated', oldValue: 2 },
- { object: array, name: '0', type: 'updated', oldValue: 3 },
- { object: array, name: '2', type: 'updated', oldValue: 1 },
- { object: array, name: '1', type: 'updated', oldValue: 3 },
- { object: array, name: '0', type: 'updated', oldValue: 2 },
+ { object: array, name: '1', type: 'update', oldValue: 2 },
+ { object: array, name: '0', type: 'update', oldValue: 3 },
+ { object: array, name: '2', type: 'update', oldValue: 1 },
+ { object: array, name: '1', type: 'update', oldValue: 3 },
+ { object: array, name: '0', type: 'update', oldValue: 2 },
]);
// Splice emitted after Array mutation methods
@@ -1434,9 +1434,9 @@
Array.prototype.push.call(array, 3, 4);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '2', type: 'new' },
- { object: array, name: '3', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
+ { object: array, name: '2', type: 'add' },
+ { object: array, name: '3', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 2 },
]);
// Pop
@@ -1449,10 +1449,10 @@
array.pop();
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '1', type: 'deleted', oldValue: 2 },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
- { object: array, name: '0', type: 'deleted', oldValue: 1 },
- { object: array, name: 'length', type: 'updated', oldValue: 1 },
+ { object: array, name: '1', type: 'delete', oldValue: 2 },
+ { object: array, name: 'length', type: 'update', oldValue: 2 },
+ { object: array, name: '0', type: 'delete', oldValue: 1 },
+ { object: array, name: 'length', type: 'update', oldValue: 1 },
]);
Object.deliverChangeRecords(observer2.callback);
observer2.assertCallbackRecords([
@@ -1470,11 +1470,11 @@
array.shift();
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '0', type: 'updated', oldValue: 1 },
- { object: array, name: '1', type: 'deleted', oldValue: 2 },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
- { object: array, name: '0', type: 'deleted', oldValue: 2 },
- { object: array, name: 'length', type: 'updated', oldValue: 1 },
+ { object: array, name: '0', type: 'update', oldValue: 1 },
+ { object: array, name: '1', type: 'delete', oldValue: 2 },
+ { object: array, name: 'length', type: 'update', oldValue: 2 },
+ { object: array, name: '0', type: 'delete', oldValue: 2 },
+ { object: array, name: 'length', type: 'update', oldValue: 1 },
]);
Object.deliverChangeRecords(observer2.callback);
observer2.assertCallbackRecords([
@@ -1491,17 +1491,17 @@
array.unshift(5);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '3', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 2 },
- { object: array, name: '2', type: 'new' },
- { object: array, name: '0', type: 'updated', oldValue: 1 },
- { object: array, name: '1', type: 'updated', oldValue: 2 },
- { object: array, name: '4', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 4 },
- { object: array, name: '3', type: 'updated', oldValue: 2 },
- { object: array, name: '2', type: 'updated', oldValue: 1 },
- { object: array, name: '1', type: 'updated', oldValue: 4 },
- { object: array, name: '0', type: 'updated', oldValue: 3 },
+ { object: array, name: '3', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 2 },
+ { object: array, name: '2', type: 'add' },
+ { object: array, name: '0', type: 'update', oldValue: 1 },
+ { object: array, name: '1', type: 'update', oldValue: 2 },
+ { object: array, name: '4', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 4 },
+ { object: array, name: '3', type: 'update', oldValue: 2 },
+ { object: array, name: '2', type: 'update', oldValue: 1 },
+ { object: array, name: '1', type: 'update', oldValue: 4 },
+ { object: array, name: '0', type: 'update', oldValue: 3 },
]);
Object.deliverChangeRecords(observer2.callback);
observer2.assertCallbackRecords([
@@ -1520,21 +1520,21 @@
array.splice(2, 0);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '4', type: 'new' },
- { object: array, name: 'length', type: 'updated', oldValue: 3 },
- { object: array, name: '3', type: 'new' },
- { object: array, name: '1', type: 'updated', oldValue: 2 },
- { object: array, name: '2', type: 'updated', oldValue: 3 },
+ { object: array, name: '4', type: 'add' },
+ { object: array, name: 'length', type: 'update', oldValue: 3 },
+ { object: array, name: '3', type: 'add' },
+ { object: array, name: '1', type: 'update', oldValue: 2 },
+ { object: array, name: '2', type: 'update', oldValue: 3 },
- { object: array, name: '0', type: 'updated', oldValue: 1 },
- { object: array, name: '1', type: 'updated', oldValue: 4 },
- { object: array, name: '2', type: 'updated', oldValue: 5 },
- { object: array, name: '4', type: 'deleted', oldValue: 3 },
- { object: array, name: '3', type: 'deleted', oldValue: 2 },
- { object: array, name: 'length', type: 'updated', oldValue: 5 },
+ { object: array, name: '0', type: 'update', oldValue: 1 },
+ { object: array, name: '1', type: 'update', oldValue: 4 },
+ { object: array, name: '2', type: 'update', oldValue: 5 },
+ { object: array, name: '4', type: 'delete', oldValue: 3 },
+ { object: array, name: '3', type: 'delete', oldValue: 2 },
+ { object: array, name: 'length', type: 'update', oldValue: 5 },
- { object: array, name: '1', type: 'updated', oldValue: 2 },
- { object: array, name: '2', type: 'updated', oldValue: 3 },
+ { object: array, name: '1', type: 'update', oldValue: 2 },
+ { object: array, name: '2', type: 'update', oldValue: 3 },
]);
Object.deliverChangeRecords(observer2.callback);
observer2.assertCallbackRecords([
@@ -1553,8 +1553,8 @@
array.splice(0, 1);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: array, name: '0', type: 'deleted', oldValue: 0 },
- { object: array, name: 'length', type: 'updated', oldValue: 1},
+ { object: array, name: '0', type: 'delete', oldValue: 0 },
+ { object: array, name: 'length', type: 'update', oldValue: 1},
]);
@@ -1572,10 +1572,10 @@
// once we support observing the global object.
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, name: '__proto__', type: 'prototype',
+ { object: obj, name: '__proto__', type: 'setPrototype',
oldValue: Object.prototype },
- { object: obj, name: '__proto__', type: 'prototype', oldValue: p },
- { object: obj, name: '__proto__', type: 'new' },
+ { object: obj, name: '__proto__', type: 'setPrototype', oldValue: p },
+ { object: obj, name: '__proto__', type: 'add' },
]);
@@ -1594,7 +1594,7 @@
// lazy creation of oldValue
assertSame(fun, observer.records[0].object);
assertEquals('prototype', observer.records[0].name);
-assertEquals('updated', observer.records[0].type);
+assertEquals('update', observer.records[0].type);
// The only existing reference to the oldValue object is in this
// record, so to test that lazy creation happened correctly
// we compare its constructor to our function (one of the invariants
@@ -1602,8 +1602,8 @@
assertSame(fun, observer.records[0].oldValue.constructor);
observer.records.splice(0, 1);
observer.assertCallbackRecords([
- { object: fun, name: 'prototype', type: 'updated', oldValue: myproto },
- { object: fun, name: 'prototype', type: 'updated', oldValue: 7 },
+ { object: fun, name: 'prototype', type: 'update', oldValue: myproto },
+ { object: fun, name: 'prototype', type: 'update', oldValue: 7 },
]);
// Function.prototype should not be observable except on the object itself
@@ -1649,7 +1649,7 @@
setElement(arr, prop, 989898);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: arr, name: "" + prop, type: 'updated', oldValue: 5 }
+ { object: arr, name: "" + prop, type: 'update', oldValue: 5 }
]);
}
@@ -1706,7 +1706,7 @@
var lengthRecord = observer.records[count];
assertSame(arr, lengthRecord.object);
assertEquals('length', lengthRecord.name);
- assertEquals('updated', lengthRecord.type);
+ assertEquals('update', lengthRecord.type);
assertSame(oldSize, lengthRecord.oldValue);
}
}
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index 7d91d74..d975f2b 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -30,9 +30,6 @@
# All tests in the bug directory are expected to fail.
'bugs/*': [FAIL],
- # TODO(mvstanton) Re-enable when the performance is bearable again.
- 'regress/regress-2185-2': [SKIP],
-
##############################################################################
# Flaky tests.
# BUG(v8:2921).
diff --git a/test/mjsunit/regress/regress-2984.js b/test/mjsunit/regress/regress-2984.js
new file mode 100644
index 0000000..de7895d
--- /dev/null
+++ b/test/mjsunit/regress/regress-2984.js
@@ -0,0 +1,34 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertEquals("\u0178", "\xff".toUpperCase());
+assertEquals("abcdefghijklmn\xffopq",
+ ("ABCDEFGHIJKL" + "MN\u0178OPQ").toLowerCase());
+assertEquals("\xff", "\u0178".toLowerCase());
+assertEquals("ABCDEFGHIJKLMN\u0178OPQ",
+ ("abcdefghijk" + "lmn\xffopq").toUpperCase());
+
diff --git a/test/mjsunit/regress/regress-2987.js b/test/mjsunit/regress/regress-2987.js
new file mode 100644
index 0000000..7dd727e
--- /dev/null
+++ b/test/mjsunit/regress/regress-2987.js
@@ -0,0 +1,57 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --dead-code-elimination
+
+// This tests that stores on captured objects are correctly tracked even
+// when DCE is enabled. We cannot delete simulations of captured objects
+// that are still needed to replay the environment correctly.
+
+function constructor() {
+ this.x = 0;
+}
+
+var deopt = { deopt:false };
+function boogeyman(mode, value) {
+ var object = new constructor();
+ if (mode) {
+ object.x = 1;
+ } else {
+ object.x = 2;
+ }
+ deopt.deopt;
+ assertEquals(value, object.x);
+}
+
+boogeyman(true, 1);
+boogeyman(true, 1);
+boogeyman(false, 2);
+boogeyman(false, 2);
+%OptimizeFunctionOnNextCall(boogeyman);
+boogeyman(false, 2);
+delete deopt.deopt;
+boogeyman(false, 2);
diff --git a/test/mjsunit/setters-on-elements.js b/test/mjsunit/setters-on-elements.js
new file mode 100644
index 0000000..dd3fabf
--- /dev/null
+++ b/test/mjsunit/setters-on-elements.js
@@ -0,0 +1,199 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --max-opt-count=100 --noalways-opt
+
+// We specify max-opt-count because we opt/deopt the same function many
+// times.
+
+// It's nice to run this in other browsers too.
+var standalone = false;
+if (standalone) {
+ assertTrue = function(val) {
+ if (val != true) {
+ print("FAILURE");
+ }
+ }
+
+ assertFalse = function(val) {
+ if (val != false) {
+ print("FAILURE");
+ }
+ }
+
+ assertEquals = function(expected, val) {
+ if (expected !== val) {
+ print("FAILURE");
+ }
+ }
+
+ empty_func = function(name) { }
+ assertUnoptimized = empty_func;
+ assertOptimized = empty_func;
+
+ optimize = empty_func;
+ clearFunctionTypeFeedback = empty_func;
+ deoptimizeFunction = empty_func;
+} else {
+ optimize = function(name) {
+ %OptimizeFunctionOnNextCall(name);
+ }
+ clearFunctionTypeFeedback = function(name) {
+ %ClearFunctionTypeFeedback(name);
+ }
+ deoptimizeFunction = function(name) {
+ %DeoptimizeFunction(name);
+ }
+}
+
+function base_setter_test(create_func, index, store_value) {
+ var calls = 0;
+
+ // Testcase: setter in prototype chain
+ foo = function(a) { a[index] = store_value; }
+ var a = create_func();
+ var ap = [];
+ ap.__defineSetter__(index, function() { calls++; });
+
+ foo(a);
+ foo(a);
+ foo(a);
+ delete a[index];
+
+ assertEquals(0, calls);
+ a.__proto__ = ap;
+ foo(a);
+ assertEquals(1, calls);
+ optimize(foo);
+ foo(a);
+ assertEquals(2, calls);
+ assertOptimized(foo);
+
+ // Testcase: setter added on prototype chain object already in place.
+ clearFunctionTypeFeedback(foo);
+ deoptimizeFunction(foo);
+ clearFunctionTypeFeedback(foo);
+ calls = 0;
+ a = create_func();
+ var apap = [];
+ a.__proto__ = apap;
+ foo(a);
+ foo(a);
+ foo(a);
+ delete a[index];
+ apap.__defineSetter__(index, function() { calls++; });
+ foo(a);
+ foo(a);
+ foo(a);
+ assertEquals(3, calls);
+
+ // Testcase: setter "deep" in prototype chain.
+ clearFunctionTypeFeedback(foo);
+ deoptimizeFunction(foo);
+ clearFunctionTypeFeedback(foo);
+ calls = 0;
+
+ a = create_func();
+ var ap2 = [];
+ a.__proto__ = ap2;
+ foo(a);
+ foo(a);
+ foo(a);
+ delete a[index];
+
+ assertEquals(0, calls);
+
+ ap2.__proto__ = ap; // "sneak" in a callback.
+ // The sneak case should be caught by unoptimized code too.
+ assertUnoptimized(foo);
+ foo(a);
+ foo(a);
+ foo(a);
+ assertEquals(3, calls);
+
+ // Testcase: setter added after optimization (feedback is monomorphic)
+ clearFunctionTypeFeedback(foo);
+ deoptimizeFunction(foo);
+ clearFunctionTypeFeedback(foo);
+ calls = 0;
+
+ a = create_func();
+ ap2 = [];
+ a.__proto__ = ap2;
+ foo(a);
+ foo(a);
+ foo(a);
+ optimize(foo);
+ foo(a);
+ assertOptimized(foo);
+ delete a[index];
+ ap2.__proto__ = ap;
+ foo(a);
+ assertUnoptimized(foo); // map shape change should deopt foo.
+ assertEquals(1, calls);
+
+ // Testcase: adding additional setters to a prototype chain that already has
+ // one shouldn't deopt anything. (ie, we aren't changing the map shape).
+ clearFunctionTypeFeedback(foo);
+ calls = 0;
+
+ a = create_func();
+ a.__proto__ = ap2;
+ bar = function(a) { a[index+1] = store_value; }
+ bar(a);
+ bar(a);
+ bar(a); // store should be generic
+ optimize(bar);
+ bar(a);
+ assertOptimized(bar);
+ assertEquals(0, calls);
+ delete a[index+1];
+ ap2.__defineSetter__(index+1, function() { calls++; });
+ bar(a);
+ assertOptimized(bar);
+ assertEquals(1, calls);
+}
+
+// Verify that map transitions don't confuse us.
+create_func_smi = function() { return [,,,,,,5]; }
+create_func_double = function() { return [0,,3.2,,,,5.5]; }
+create_func_fast = function() { return [,,,,,,true]; }
+create_func_dictionary = function() { var a = []; a.length = 100000; return a; }
+
+var cf = [create_func_smi,
+ create_func_double,
+ create_func_fast,
+ create_func_dictionary];
+
+var values = [3, 3.5, true];
+
+for(var c = 0; c < 3; c++) {
+ for(var s = 0; s < 3; s++) {
+ base_setter_test(cf[c], 0, values[s]);
+ base_setter_test(cf[c], 1, values[s]);
+ }
+}
diff --git a/test/mjsunit/string-natives.js b/test/mjsunit/string-natives.js
index b1ec875..cd1cde1 100644
--- a/test/mjsunit/string-natives.js
+++ b/test/mjsunit/string-natives.js
@@ -29,15 +29,23 @@
function test() {
var s1 = %NewString(26, true);
+ for (i = 0; i < 26; i++) %_OneByteSeqStringSetChar(s1, i, 65);
+ assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAA", s1);
+ %_OneByteSeqStringSetChar(s1, 25, 66);
+ assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAB", s1);
for (i = 0; i < 26; i++) %_OneByteSeqStringSetChar(s1, i, i+65);
assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", s1);
s1 = %TruncateString(s1, 13);
assertEquals("ABCDEFGHIJKLM", s1);
var s2 = %NewString(26, false);
+ for (i = 0; i < 26; i++) %_TwoByteSeqStringSetChar(s2, i, 65);
+ assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAA", s2);
+ %_TwoByteSeqStringSetChar(s2, 25, 66);
+ assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAB", s2);
for (i = 0; i < 26; i++) %_TwoByteSeqStringSetChar(s2, i, i+65);
assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", s2);
- s2 = %TruncateString(s1, 13);
+ s2 = %TruncateString(s2, 13);
assertEquals("ABCDEFGHIJKLM", s2);
var s3 = %NewString(26, false);
diff --git a/test/webkit/fast/js/array-bad-time-expected.txt b/test/webkit/fast/js/array-bad-time-expected.txt
index 7668e7e..478c9a8 100644
--- a/test/webkit/fast/js/array-bad-time-expected.txt
+++ b/test/webkit/fast/js/array-bad-time-expected.txt
@@ -977,58 +977,57 @@
PASS "0,1,2,3,4" is "0,1,2,3,4"
PASS "0,1,2,3,4" is "0,1,2,3,4"
Henceforth I will have a bad time.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL ouches should be 50. Was 0.
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS ouches is 50
PASS successfullyParsed is true
TEST COMPLETE
-
diff --git a/test/webkit/fast/js/array-bad-time.js b/test/webkit/fast/js/array-bad-time.js
index 1d3802e..26241b2 100644
--- a/test/webkit/fast/js/array-bad-time.js
+++ b/test/webkit/fast/js/array-bad-time.js
@@ -33,7 +33,7 @@
for (var i = 0; i < result.length; ++i) {
if (i == haveABadTime) {
debug("Henceforth I will have a bad time.");
- Array.prototype.__defineSetter__("3", function() { debug("Ouch!"); ouches++; });
+ Array.prototype.__defineSetter__("3", function() { ouches++; });
}
result[i] = i;
}
diff --git a/test/webkit/fast/js/array-slow-put-expected.txt b/test/webkit/fast/js/array-slow-put-expected.txt
index 4748462..99b44c3 100644
--- a/test/webkit/fast/js/array-slow-put-expected.txt
+++ b/test/webkit/fast/js/array-slow-put-expected.txt
@@ -26,108 +26,107 @@
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL ouches should be 100. Was 0.
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS ouches is 100
PASS successfullyParsed is true
TEST COMPLETE
-
diff --git a/test/webkit/fast/js/array-slow-put.js b/test/webkit/fast/js/array-slow-put.js
index 1e8c44d..63bcad0 100644
--- a/test/webkit/fast/js/array-slow-put.js
+++ b/test/webkit/fast/js/array-slow-put.js
@@ -26,7 +26,7 @@
);
var ouches = 0;
-Array.prototype.__defineSetter__("3", function() { debug("Ouch!"); ouches++; });
+Array.prototype.__defineSetter__("3", function() { ouches++; });
function foo() {
var result = [];
diff --git a/test/webkit/fast/js/object-bad-time-expected.txt b/test/webkit/fast/js/object-bad-time-expected.txt
index b282bd8..7b6b6ea 100644
--- a/test/webkit/fast/js/object-bad-time-expected.txt
+++ b/test/webkit/fast/js/object-bad-time-expected.txt
@@ -977,58 +977,57 @@
PASS "0,1,2,3,4" is "0,1,2,3,4"
PASS "0,1,2,3,4" is "0,1,2,3,4"
Henceforth I will have a bad time.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL ouches should be 50. Was 0.
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS ouches is 50
PASS successfullyParsed is true
TEST COMPLETE
-
diff --git a/test/webkit/fast/js/object-bad-time.js b/test/webkit/fast/js/object-bad-time.js
index 2fdb2d1..45fb4dd 100644
--- a/test/webkit/fast/js/object-bad-time.js
+++ b/test/webkit/fast/js/object-bad-time.js
@@ -36,7 +36,7 @@
for (var i = 0; i < result.length; ++i) {
if (i == haveABadTime) {
debug("Henceforth I will have a bad time.");
- Cons.prototype.__defineSetter__("3", function() { debug("Ouch!"); ouches++; });
+ Cons.prototype.__defineSetter__("3", function() { ouches++; });
}
result[i] = i;
}
diff --git a/test/webkit/fast/js/object-slow-put-expected.txt b/test/webkit/fast/js/object-slow-put-expected.txt
index 901133b..f20c4a5 100644
--- a/test/webkit/fast/js/object-slow-put-expected.txt
+++ b/test/webkit/fast/js/object-slow-put-expected.txt
@@ -26,108 +26,107 @@
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL "0,1,2,3,4" should be 0,1,2,,4. Was 0,1,2,3,4.
-FAIL ouches should be 100. Was 0.
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS "0,1,2,,4" is "0,1,2,,4"
+PASS ouches is 100
PASS successfullyParsed is true
TEST COMPLETE
-
diff --git a/test/webkit/fast/js/object-slow-put.js b/test/webkit/fast/js/object-slow-put.js
index bf8234f..49c20ba 100644
--- a/test/webkit/fast/js/object-slow-put.js
+++ b/test/webkit/fast/js/object-slow-put.js
@@ -29,7 +29,7 @@
}
var ouches = 0;
-Cons.prototype.__defineSetter__("3", function() { debug("Ouch!"); ouches++; });
+Cons.prototype.__defineSetter__("3", function() { ouches++; });
function foo() {
var result = new Cons();
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 22fcf94..5baa245 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -28,6 +28,7 @@
{
'variables': {
'v8_code': 1,
+ 'v8_random_seed%': 314159265,
},
'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
'targets': [
@@ -156,6 +157,11 @@
'--log-snapshot-positions',
'--logfile', '<(INTERMEDIATE_DIR)/snapshot.log',
],
+ 'conditions': [
+ ['v8_random_seed!=0', {
+ 'mksnapshot_flags': ['--random-seed', '<(v8_random_seed)'],
+ }],
+ ],
},
'action': [
'<@(_inputs)',