Update V8 to r4730 as required by WebKit r60469
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index d9586cc..767c33f 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -27,6 +27,8 @@
#include "v8.h"
+#if defined(V8_TARGET_ARCH_X64)
+
#include "bootstrapper.h"
#include "codegen-inl.h"
#include "compiler.h"
@@ -601,9 +603,8 @@
public:
explicit DeferredReferenceGetKeyedValue(Register dst,
Register receiver,
- Register key,
- bool is_global)
- : dst_(dst), receiver_(receiver), key_(key), is_global_(is_global) {
+ Register key)
+ : dst_(dst), receiver_(receiver), key_(key) {
set_comment("[ DeferredReferenceGetKeyedValue");
}
@@ -616,7 +617,6 @@
Register dst_;
Register receiver_;
Register key_;
- bool is_global_;
};
@@ -631,10 +631,7 @@
// This means that we cannot allow test instructions after calls to
// KeyedLoadIC stubs in other places.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
- RelocInfo::Mode mode = is_global_
- ? RelocInfo::CODE_TARGET_CONTEXT
- : RelocInfo::CODE_TARGET;
- __ Call(ic, mode);
+ __ Call(ic, RelocInfo::CODE_TARGET);
// The delta from the start of the map-compare instruction to the
// test instruction. We use masm_-> directly here instead of the __
// macro because the macro sometimes uses macro expansion to turn
@@ -678,11 +675,51 @@
void DeferredReferenceSetKeyedValue::Generate() {
__ IncrementCounter(&Counters::keyed_store_inline_miss, 1);
- // Push receiver and key arguments on the stack.
- __ push(receiver_);
- __ push(key_);
- // Move value argument to eax as expected by the IC stub.
- if (!value_.is(rax)) __ movq(rax, value_);
+ // Move value, receiver, and key to registers rax, rdx, and rcx, as
+ // the IC stub expects.
+ // Move value to rax, using xchg if the receiver or key is in rax.
+ if (!value_.is(rax)) {
+ if (!receiver_.is(rax) && !key_.is(rax)) {
+ __ movq(rax, value_);
+ } else {
+ __ xchg(rax, value_);
+ // Update receiver_ and key_ if they are affected by the swap.
+ if (receiver_.is(rax)) {
+ receiver_ = value_;
+ } else if (receiver_.is(value_)) {
+ receiver_ = rax;
+ }
+ if (key_.is(rax)) {
+ key_ = value_;
+ } else if (key_.is(value_)) {
+ key_ = rax;
+ }
+ }
+ }
+ // Value is now in rax. Its original location is remembered in value_,
+ // and the value is restored to value_ before returning.
+ // The variables receiver_ and key_ are not preserved.
+ // Move receiver and key to rdx and rcx, swapping if necessary.
+ if (receiver_.is(rdx)) {
+ if (!key_.is(rcx)) {
+ __ movq(rcx, key_);
+ } // Else everything is already in the right place.
+ } else if (receiver_.is(rcx)) {
+ if (key_.is(rdx)) {
+ __ xchg(rcx, rdx);
+ } else if (key_.is(rcx)) {
+ __ movq(rdx, receiver_);
+ } else {
+ __ movq(rdx, receiver_);
+ __ movq(rcx, key_);
+ }
+ } else if (key_.is(rcx)) {
+ __ movq(rdx, receiver_);
+ } else {
+ __ movq(rcx, key_);
+ __ movq(rdx, receiver_);
+ }
+
// Call the IC stub.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
@@ -695,11 +732,8 @@
// Here we use masm_-> instead of the __ macro because this is the
// instruction that gets patched and coverage code gets in the way.
masm_->testl(rax, Immediate(-delta_to_patch_site));
- // Restore value (returned from store IC), key and receiver
- // registers.
+ // Restore value (returned from store IC).
if (!value_.is(rax)) __ movq(value_, rax);
- __ pop(key_);
- __ pop(receiver_);
}
@@ -1546,7 +1580,7 @@
}
Result var = frame_->Pop();
var.ToRegister();
- __ AbortIfNotSmi(var.reg(), "Non-smi value in smi-typed stack slot.");
+ __ AbortIfNotSmi(var.reg());
}
}
@@ -2799,6 +2833,7 @@
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Load(args->at(i));
+ frame_->SpillTop();
}
// Prepare the stack for the call to ResolvePossiblyDirectEval.
@@ -2848,6 +2883,7 @@
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Load(args->at(i));
+ frame_->SpillTop();
}
// Push the name of the function on the frame.
@@ -2953,6 +2989,7 @@
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Load(args->at(i));
+ frame_->SpillTop();
}
// Push the name of the function onto the frame.
@@ -3399,7 +3436,11 @@
new_value.type_info());
}
- __ JumpIfNotSmi(new_value.reg(), deferred->entry_label());
+ if (new_value.is_smi()) {
+ if (FLAG_debug_code) { __ AbortIfNotSmi(new_value.reg()); }
+ } else {
+ __ JumpIfNotSmi(new_value.reg(), deferred->entry_label());
+ }
if (is_increment) {
__ SmiAddConstant(kScratchRegister,
new_value.reg(),
@@ -3833,11 +3874,13 @@
__ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
destination()->false_target()->Branch(not_zero);
- __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE);
- destination()->false_target()->Branch(less);
- __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
+ __ movzxbq(kScratchRegister,
+ FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
+ __ cmpq(kScratchRegister, Immediate(FIRST_JS_OBJECT_TYPE));
+ destination()->false_target()->Branch(below);
+ __ cmpq(kScratchRegister, Immediate(LAST_JS_OBJECT_TYPE));
obj.Unuse();
- destination()->Split(less_equal);
+ destination()->Split(below_equal);
}
@@ -3921,7 +3964,7 @@
__ bind(&exit);
result.set_type_info(TypeInfo::Smi());
if (FLAG_debug_code) {
- __ AbortIfNotSmi(result.reg(), "Computed arguments.length is not a smi.");
+ __ AbortIfNotSmi(result.reg());
}
frame_->Push(&result);
}
@@ -4329,7 +4372,7 @@
__ PrepareCallCFunction(0);
__ CallCFunction(ExternalReference::random_uint32_function(), 0);
- // Convert 32 random bits in eax to 0.(32 random bits) in a double
+ // Convert 32 random bits in rax to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
__ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
@@ -5100,10 +5143,9 @@
value.ToRegister();
if (value.is_number()) {
- Comment cmnt(masm_, "ONLY_NUMBER");
// Fast case if TypeInfo indicates only numbers.
if (FLAG_debug_code) {
- __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number.");
+ __ AbortIfNotNumber(value.reg());
}
// Smi => false iff zero.
__ SmiCompare(value.reg(), Smi::FromInt(0));
@@ -5646,7 +5688,7 @@
slow));
frame_->Push(&arguments);
frame_->Push(key_literal->handle());
- *result = EmitKeyedLoad(false);
+ *result = EmitKeyedLoad();
frame_->Drop(2); // Drop key and receiver.
done->Jump(result);
}
@@ -5876,7 +5918,7 @@
if (left_side.is_smi()) {
if (FLAG_debug_code) {
- __ AbortIfNotSmi(left_side.reg(), "Non-smi value inferred as smi.");
+ __ AbortIfNotSmi(left_side.reg());
}
} else {
Condition left_is_smi = masm_->CheckSmi(left_side.reg());
@@ -6748,8 +6790,7 @@
Condition is_smi = masm_->CheckSmi(operand->reg());
deferred->Branch(NegateCondition(is_smi));
} else if (FLAG_debug_code) {
- __ AbortIfNotSmi(operand->reg(),
- "Static type info claims non-smi is smi in (const SHL smi).");
+ __ AbortIfNotSmi(operand->reg());
}
__ Move(answer.reg(), smi_value);
@@ -7011,7 +7052,43 @@
left->reg(),
rcx,
overwrite_mode);
- __ JumpIfNotBothSmi(left->reg(), rcx, deferred->entry_label());
+
+ Label do_op;
+ if (right_type_info.IsSmi()) {
+ if (FLAG_debug_code) {
+ __ AbortIfNotSmi(right->reg());
+ }
+ __ movq(answer.reg(), left->reg());
+ // If left is not known to be a smi, check if it is.
+ // If left is not known to be a number, and it isn't a smi, check if
+ // it is a HeapNumber.
+ if (!left_type_info.IsSmi()) {
+ __ JumpIfSmi(answer.reg(), &do_op);
+ if (!left_type_info.IsNumber()) {
+ // Branch if not a heapnumber.
+ __ Cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset),
+ Factory::heap_number_map());
+ deferred->Branch(not_equal);
+ }
+ // Load integer value into answer register using truncation.
+ __ cvttsd2si(answer.reg(),
+ FieldOperand(answer.reg(), HeapNumber::kValueOffset));
+ // Branch if we might have overflowed.
+ // (False negative for Smi::kMinValue)
+ __ cmpq(answer.reg(), Immediate(0x80000000));
+ deferred->Branch(equal);
+ // TODO(lrn): Inline shifts on int32 here instead of first smi-tagging.
+ __ Integer32ToSmi(answer.reg(), answer.reg());
+ } else {
+ // Fast case - both are actually smis.
+ if (FLAG_debug_code) {
+ __ AbortIfNotSmi(left->reg());
+ }
+ }
+ } else {
+ __ JumpIfNotBothSmi(left->reg(), rcx, deferred->entry_label());
+ }
+ __ bind(&do_op);
// Perform the operation.
switch (op) {
@@ -7106,8 +7183,89 @@
}
-Result CodeGenerator::EmitKeyedLoad(bool is_global) {
- Comment cmnt(masm_, "[ Load from keyed Property");
+Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
+#ifdef DEBUG
+ int original_height = frame()->height();
+#endif
+ Result result;
+ // Do not inline the inobject property case for loads from the global
+ // object. Also do not inline for unoptimized code. This saves time
+ // in the code generator. Unoptimized code is toplevel code or code
+ // that is not in a loop.
+ if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
+ Comment cmnt(masm(), "[ Load from named Property");
+ frame()->Push(name);
+
+ RelocInfo::Mode mode = is_contextual
+ ? RelocInfo::CODE_TARGET_CONTEXT
+ : RelocInfo::CODE_TARGET;
+ result = frame()->CallLoadIC(mode);
+ // A test rax instruction following the call signals that the
+ // inobject property case was inlined. Ensure that there is not
+ // a test rax instruction here.
+ __ nop();
+ } else {
+ // Inline the inobject property case.
+ Comment cmnt(masm(), "[ Inlined named property load");
+ Result receiver = frame()->Pop();
+ receiver.ToRegister();
+ result = allocator()->Allocate();
+ ASSERT(result.is_valid());
+
+ // Cannot use r12 for receiver, because that changes
+ // the distance between a call and a fixup location,
+ // due to a special encoding of r12 as r/m in a ModR/M byte.
+ if (receiver.reg().is(r12)) {
+ frame()->Spill(receiver.reg()); // It will be overwritten with result.
+ // Swap receiver and value.
+ __ movq(result.reg(), receiver.reg());
+ Result temp = receiver;
+ receiver = result;
+ result = temp;
+ }
+
+ DeferredReferenceGetNamedValue* deferred =
+ new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name);
+
+ // Check that the receiver is a heap object.
+ __ JumpIfSmi(receiver.reg(), deferred->entry_label());
+
+ __ bind(deferred->patch_site());
+ // This is the map check instruction that will be patched (so we can't
+ // use the double underscore macro that may insert instructions).
+ // Initially use an invalid map to force a failure.
+ masm()->Move(kScratchRegister, Factory::null_value());
+ masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
+ kScratchRegister);
+ // This branch is always a forwards branch so it's always a fixed
+ // size which allows the assert below to succeed and patching to work.
+ // Don't use deferred->Branch(...), since that might add coverage code.
+ masm()->j(not_equal, deferred->entry_label());
+
+ // The delta from the patch label to the load offset must be
+ // statically known.
+ ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) ==
+ LoadIC::kOffsetToLoadInstruction);
+ // The initial (invalid) offset has to be large enough to force
+ // a 32-bit instruction encoding to allow patching with an
+ // arbitrary offset. Use kMaxInt (minus kHeapObjectTag).
+ int offset = kMaxInt;
+ masm()->movq(result.reg(), FieldOperand(receiver.reg(), offset));
+
+ __ IncrementCounter(&Counters::named_load_inline, 1);
+ deferred->BindExit();
+ frame()->Push(&receiver);
+ }
+ ASSERT(frame()->height() == original_height);
+ return result;
+}
+
+
+Result CodeGenerator::EmitKeyedLoad() {
+#ifdef DEBUG
+ int original_height = frame()->height();
+#endif
+ Result result;
// Inline array load code if inside of a loop. We do not know
// the receiver map yet, so we initially generate the code with
// a check against an invalid map. In the inline cache code, we
@@ -7115,34 +7273,30 @@
if (loop_nesting() > 0) {
Comment cmnt(masm_, "[ Inlined load from keyed Property");
+ // Use a fresh temporary to load the elements without destroying
+ // the receiver which is needed for the deferred slow case.
+ // Allocate the temporary early so that we use rax if it is free.
+ Result elements = allocator()->Allocate();
+ ASSERT(elements.is_valid());
+
+
Result key = frame_->Pop();
Result receiver = frame_->Pop();
key.ToRegister();
receiver.ToRegister();
- // Use a fresh temporary to load the elements without destroying
- // the receiver which is needed for the deferred slow case.
- Result elements = allocator()->Allocate();
- ASSERT(elements.is_valid());
-
- // Use a fresh temporary for the index and later the loaded
- // value.
+ // Use a fresh temporary for the index
Result index = allocator()->Allocate();
ASSERT(index.is_valid());
DeferredReferenceGetKeyedValue* deferred =
- new DeferredReferenceGetKeyedValue(index.reg(),
+ new DeferredReferenceGetKeyedValue(elements.reg(),
receiver.reg(),
- key.reg(),
- is_global);
+ key.reg());
- // Check that the receiver is not a smi (only needed if this
- // is not a load from the global context) and that it has the
- // expected map.
- if (!is_global) {
- __ JumpIfSmi(receiver.reg(), deferred->entry_label());
- }
+ __ JumpIfSmi(receiver.reg(), deferred->entry_label());
+ // Check that the receiver has the expected map.
// Initially, use an invalid map. The map is patched in the IC
// initialization code.
__ bind(deferred->patch_site());
@@ -7173,7 +7327,6 @@
__ cmpl(index.reg(),
FieldOperand(elements.reg(), FixedArray::kLengthOffset));
deferred->Branch(above_equal);
-
// The index register holds the un-smi-tagged key. It has been
// zero-extended to 64-bits, so it can be used directly as index in the
// operand below.
@@ -7184,39 +7337,33 @@
// heuristic about which register to reuse. For example, if
// one is rax, the we can reuse that one because the value
// coming from the deferred code will be in rax.
- Result value = index;
- __ movq(value.reg(),
+ __ movq(elements.reg(),
Operand(elements.reg(),
index.reg(),
times_pointer_size,
FixedArray::kHeaderSize - kHeapObjectTag));
+ result = elements;
elements.Unuse();
index.Unuse();
- __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex);
+ __ CompareRoot(result.reg(), Heap::kTheHoleValueRootIndex);
deferred->Branch(equal);
__ IncrementCounter(&Counters::keyed_load_inline, 1);
deferred->BindExit();
- // Restore the receiver and key to the frame and push the
- // result on top of it.
frame_->Push(&receiver);
frame_->Push(&key);
- return value;
-
} else {
Comment cmnt(masm_, "[ Load from keyed Property");
- RelocInfo::Mode mode = is_global
- ? RelocInfo::CODE_TARGET_CONTEXT
- : RelocInfo::CODE_TARGET;
- Result answer = frame_->CallKeyedLoadIC(mode);
+ result = frame_->CallKeyedLoadIC(RelocInfo::CODE_TARGET);
// Make sure that we do not have a test instruction after the
// call. A test instruction after the call is used to
// indicate that we have generated an inline version of the
// keyed load. The explicit nop instruction is here because
// the push that follows might be peep-hole optimized away.
__ nop();
- return answer;
}
+ ASSERT(frame()->height() == original_height);
+ return result;
}
@@ -7259,6 +7406,7 @@
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
ASSERT(slot != NULL);
cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
+ if (!persist_after_get_) set_unloaded();
break;
}
@@ -7266,101 +7414,29 @@
Variable* var = expression_->AsVariableProxy()->AsVariable();
bool is_global = var != NULL;
ASSERT(!is_global || var->is_global());
-
- // Do not inline the inobject property case for loads from the global
- // object. Also do not inline for unoptimized code. This saves time
- // in the code generator. Unoptimized code is toplevel code or code
- // that is not in a loop.
- if (is_global ||
- cgen_->scope()->is_global_scope() ||
- cgen_->loop_nesting() == 0) {
- Comment cmnt(masm, "[ Load from named Property");
- cgen_->frame()->Push(GetName());
-
- RelocInfo::Mode mode = is_global
- ? RelocInfo::CODE_TARGET_CONTEXT
- : RelocInfo::CODE_TARGET;
- Result answer = cgen_->frame()->CallLoadIC(mode);
- // A test rax instruction following the call signals that the
- // inobject property case was inlined. Ensure that there is not
- // a test rax instruction here.
- __ nop();
- cgen_->frame()->Push(&answer);
- } else {
- // Inline the inobject property case.
- Comment cmnt(masm, "[ Inlined named property load");
- Result receiver = cgen_->frame()->Pop();
- receiver.ToRegister();
- Result value = cgen_->allocator()->Allocate();
- ASSERT(value.is_valid());
- // Cannot use r12 for receiver, because that changes
- // the distance between a call and a fixup location,
- // due to a special encoding of r12 as r/m in a ModR/M byte.
- if (receiver.reg().is(r12)) {
- // Swap receiver and value.
- __ movq(value.reg(), receiver.reg());
- Result temp = receiver;
- receiver = value;
- value = temp;
- cgen_->frame()->Spill(value.reg()); // r12 may have been shared.
- }
-
- DeferredReferenceGetNamedValue* deferred =
- new DeferredReferenceGetNamedValue(value.reg(),
- receiver.reg(),
- GetName());
-
- // Check that the receiver is a heap object.
- __ JumpIfSmi(receiver.reg(), deferred->entry_label());
-
- __ bind(deferred->patch_site());
- // This is the map check instruction that will be patched (so we can't
- // use the double underscore macro that may insert instructions).
- // Initially use an invalid map to force a failure.
- masm->Move(kScratchRegister, Factory::null_value());
- masm->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
- kScratchRegister);
- // This branch is always a forwards branch so it's always a fixed
- // size which allows the assert below to succeed and patching to work.
- // Don't use deferred->Branch(...), since that might add coverage code.
- masm->j(not_equal, deferred->entry_label());
-
- // The delta from the patch label to the load offset must be
- // statically known.
- ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) ==
- LoadIC::kOffsetToLoadInstruction);
- // The initial (invalid) offset has to be large enough to force
- // a 32-bit instruction encoding to allow patching with an
- // arbitrary offset. Use kMaxInt (minus kHeapObjectTag).
- int offset = kMaxInt;
- masm->movq(value.reg(), FieldOperand(receiver.reg(), offset));
-
- __ IncrementCounter(&Counters::named_load_inline, 1);
- deferred->BindExit();
- cgen_->frame()->Push(&receiver);
- cgen_->frame()->Push(&value);
+ Result result = cgen_->EmitNamedLoad(GetName(), is_global);
+ cgen_->frame()->Push(&result);
+ if (!persist_after_get_) {
+ cgen_->UnloadReference(this);
}
break;
}
case KEYED: {
- Comment cmnt(masm, "[ Load from keyed Property");
- Variable* var = expression_->AsVariableProxy()->AsVariable();
- bool is_global = var != NULL;
- ASSERT(!is_global || var->is_global());
+ // A load of a bare identifier (load from global) cannot be keyed.
+ ASSERT(expression_->AsVariableProxy()->AsVariable() == NULL);
- Result value = cgen_->EmitKeyedLoad(is_global);
+ Result value = cgen_->EmitKeyedLoad();
cgen_->frame()->Push(&value);
+ if (!persist_after_get_) {
+ cgen_->UnloadReference(this);
+ }
break;
}
default:
UNREACHABLE();
}
-
- if (!persist_after_get_) {
- cgen_->UnloadReference(this);
- }
}
@@ -7469,7 +7545,7 @@
if (!key.is_smi()) {
__ JumpIfNotSmi(key.reg(), deferred->entry_label());
} else if (FLAG_debug_code) {
- __ AbortIfNotSmi(key.reg(), "Non-smi value in smi-typed value.");
+ __ AbortIfNotSmi(key.reg());
}
// Check that the receiver is a JSArray.
@@ -7524,8 +7600,6 @@
deferred->BindExit();
- cgen_->frame()->Push(&receiver);
- cgen_->frame()->Push(&key);
cgen_->frame()->Push(&value);
} else {
Result answer = cgen_->frame()->CallKeyedStoreIC();
@@ -7536,7 +7610,7 @@
masm->nop();
cgen_->frame()->Push(&answer);
}
- cgen_->UnloadReference(this);
+ set_unloaded();
break;
}
@@ -8898,6 +8972,7 @@
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Load(args->at(i));
+ frame_->SpillTop();
}
// Record the position for debugging purposes.
@@ -10014,8 +10089,8 @@
if (static_operands_type_.IsSmi()) {
// Skip smi check if we know that both arguments are smis.
if (FLAG_debug_code) {
- __ AbortIfNotSmi(left, "Static type check claimed non-smi is smi.");
- __ AbortIfNotSmi(right, "Static type check claimed non-smi is smi.");
+ __ AbortIfNotSmi(left);
+ __ AbortIfNotSmi(right);
}
if (op_ == Token::BIT_OR) {
// Handle OR here, since we do extra smi-checking in the or code below.
@@ -10198,8 +10273,8 @@
// rdx: x
if (static_operands_type_.IsNumber() && FLAG_debug_code) {
// Assert at runtime that inputs are only numbers.
- __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number.");
- __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number.");
+ __ AbortIfNotNumber(rdx);
+ __ AbortIfNotNumber(rax);
} else {
FloatingPointHelper::CheckNumberOperands(masm, &call_runtime);
}
@@ -11589,3 +11664,5 @@
#undef __
} } // namespace v8::internal
+
+#endif // V8_TARGET_ARCH_X64