vendor/v8/src/ia32/lithium-codegen-ia32.cc in mustang-0.0.1 vs vendor/v8/src/ia32/lithium-codegen-ia32.cc in mustang-0.1.0
- old
+ new
@@ -29,10 +29,11 @@
#if defined(V8_TARGET_ARCH_IA32)
#include "ia32/lithium-codegen-ia32.h"
#include "code-stubs.h"
+#include "deoptimizer.h"
#include "stub-cache.h"
namespace v8 {
namespace internal {
@@ -41,32 +42,24 @@
// the invoke instruction sequence generated by the macro assembler.
class SafepointGenerator : public PostCallGenerator {
public:
SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers,
- int deoptimization_index,
- bool ensure_reloc_space = false)
+ int deoptimization_index)
: codegen_(codegen),
pointers_(pointers),
- deoptimization_index_(deoptimization_index),
- ensure_reloc_space_(ensure_reloc_space) { }
+ deoptimization_index_(deoptimization_index) {}
virtual ~SafepointGenerator() { }
virtual void Generate() {
- // Ensure that we have enough space in the reloc info to patch
- // this with calls when doing deoptimization.
- if (ensure_reloc_space_) {
- codegen_->EnsureRelocSpaceForDeoptimization();
- }
codegen_->RecordSafepoint(pointers_, deoptimization_index_);
}
private:
LCodeGen* codegen_;
LPointerMap* pointers_;
int deoptimization_index_;
- bool ensure_reloc_space_;
};
#define __ masm()->
@@ -76,27 +69,27 @@
status_ = GENERATING;
CpuFeatures::Scope scope(SSE2);
return GeneratePrologue() &&
GenerateBody() &&
GenerateDeferredCode() &&
- GenerateRelocPadding() &&
GenerateSafepointTable();
}
void LCodeGen::FinishCode(Handle<Code> code) {
ASSERT(is_done());
code->set_stack_slots(StackSlotCount());
code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code);
+ Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
}
void LCodeGen::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
- PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name);
+ SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ PrintF("Aborting LCodeGen in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
OS::VPrint(format, arguments);
va_end(arguments);
PrintF("\n");
@@ -121,20 +114,10 @@
memcpy(copy.start(), builder.Finalize(), copy.length());
masm()->RecordComment(copy.start());
}
-bool LCodeGen::GenerateRelocPadding() {
- int reloc_size = masm()->relocation_writer_size();
- while (reloc_size < deoptimization_reloc_size.min_size) {
- __ RecordComment(RelocInfo::kFillerCommentString, true);
- reloc_size += RelocInfo::kRelocCommentSize;
- }
- return !is_aborted();
-}
-
-
bool LCodeGen::GeneratePrologue() {
ASSERT(is_generating());
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
@@ -383,26 +366,10 @@
AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
}
}
-void LCodeGen::EnsureRelocSpaceForDeoptimization() {
- // Since we patch the reloc info with RUNTIME_ENTRY calls every patch
- // site will take up 2 bytes + any pc-jumps.
- // We are conservative and always reserver 6 bytes in case where a
- // simple pc-jump is not enough.
- uint32_t pc_delta =
- masm()->pc_offset() - deoptimization_reloc_size.last_pc_offset;
- if (is_uintn(pc_delta, 6)) {
- deoptimization_reloc_size.min_size += 2;
- } else {
- deoptimization_reloc_size.min_size += 6;
- }
- deoptimization_reloc_size.last_pc_offset = masm()->pc_offset();
-}
-
-
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged) {
if (op == NULL) {
// TODO(twuerthinger): Introduce marker operands to indicate that this value
@@ -452,11 +419,10 @@
if (!adjusted) {
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
__ call(code, mode);
- EnsureRelocSpaceForDeoptimization();
RegisterLazyDeoptimization(instr);
// Signal that we don't inline smi code before these stubs in the
// optimizing code generator.
if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC ||
@@ -464,11 +430,11 @@
__ nop();
}
}
-void LCodeGen::CallRuntime(Runtime::Function* fun,
+void LCodeGen::CallRuntime(const Runtime::Function* fun,
int argc,
LInstruction* instr,
bool adjusted) {
ASSERT(instr != NULL);
ASSERT(instr->HasPointerMap());
@@ -477,10 +443,11 @@
if (!adjusted) {
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
__ CallRuntime(fun, argc);
+
RegisterLazyDeoptimization(instr);
}
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) {
@@ -584,17 +551,18 @@
void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
int length = deoptimizations_.length();
if (length == 0) return;
ASSERT(FLAG_deopt);
Handle<DeoptimizationInputData> data =
- Factory::NewDeoptimizationInputData(length, TENURED);
+ factory()->NewDeoptimizationInputData(length, TENURED);
- data->SetTranslationByteArray(*translations_.CreateByteArray());
+ Handle<ByteArray> translations = translations_.CreateByteArray();
+ data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
Handle<FixedArray> literals =
- Factory::NewFixedArray(deoptimization_literals_.length(), TENURED);
+ factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
for (int i = 0; i < deoptimization_literals_.length(); i++) {
literals->set(i, *deoptimization_literals_[i]);
}
data->SetLiteralArray(*literals);
@@ -740,20 +708,10 @@
case CodeStub::SubString: {
SubStringStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
break;
}
- case CodeStub::StringCharAt: {
- StringCharAtStub stub;
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- break;
- }
- case CodeStub::MathPow: {
- MathPowStub stub;
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- break;
- }
case CodeStub::NumberToString: {
NumberToStringStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
break;
}
@@ -783,45 +741,68 @@
// Nothing to do.
}
void LCodeGen::DoModI(LModI* instr) {
- LOperand* right = instr->InputAt(1);
- ASSERT(ToRegister(instr->result()).is(edx));
- ASSERT(ToRegister(instr->InputAt(0)).is(eax));
- ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
- ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
+ if (instr->hydrogen()->HasPowerOf2Divisor()) {
+ Register dividend = ToRegister(instr->InputAt(0));
- Register right_reg = ToRegister(right);
+ int32_t divisor =
+ HConstant::cast(instr->hydrogen()->right())->Integer32Value();
- // Check for x % 0.
- if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ test(right_reg, ToOperand(right));
- DeoptimizeIf(zero, instr->environment());
- }
+ if (divisor < 0) divisor = -divisor;
- // Sign extend to edx.
- __ cdq();
+ NearLabel positive_dividend, done;
+ __ test(dividend, Operand(dividend));
+ __ j(not_sign, &positive_dividend);
+ __ neg(dividend);
+ __ and_(dividend, divisor - 1);
+ __ neg(dividend);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ j(not_zero, &done);
+ DeoptimizeIf(no_condition, instr->environment());
+ }
+ __ bind(&positive_dividend);
+ __ and_(dividend, divisor - 1);
+ __ bind(&done);
+ } else {
+ LOperand* right = instr->InputAt(1);
+ ASSERT(ToRegister(instr->InputAt(0)).is(eax));
+ ASSERT(ToRegister(instr->result()).is(edx));
- // Check for (0 % -x) that will produce negative zero.
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- NearLabel positive_left;
- NearLabel done;
- __ test(eax, Operand(eax));
- __ j(not_sign, &positive_left);
- __ idiv(right_reg);
+ Register right_reg = ToRegister(right);
+ ASSERT(!right_reg.is(eax));
+ ASSERT(!right_reg.is(edx));
- // Test the remainder for 0, because then the result would be -0.
- __ test(edx, Operand(edx));
- __ j(not_zero, &done);
+ // Check for x % 0.
+ if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ test(right_reg, ToOperand(right));
+ DeoptimizeIf(zero, instr->environment());
+ }
- DeoptimizeIf(no_condition, instr->environment());
- __ bind(&positive_left);
- __ idiv(right_reg);
- __ bind(&done);
- } else {
- __ idiv(right_reg);
+ // Sign extend to edx.
+ __ cdq();
+
+ // Check for (0 % -x) that will produce negative zero.
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ NearLabel positive_left;
+ NearLabel done;
+ __ test(eax, Operand(eax));
+ __ j(not_sign, &positive_left);
+ __ idiv(right_reg);
+
+ // Test the remainder for 0, because then the result would be -0.
+ __ test(edx, Operand(edx));
+ __ j(not_zero, &done);
+
+ DeoptimizeIf(no_condition, instr->environment());
+ __ bind(&positive_left);
+ __ idiv(right_reg);
+ __ bind(&done);
+ } else {
+ __ idiv(right_reg);
+ }
}
}
void LCodeGen::DoDivI(LDivI* instr) {
@@ -877,11 +858,53 @@
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ mov(ToRegister(instr->TempAt(0)), left);
}
if (right->IsConstantOperand()) {
- __ imul(left, left, ToInteger32(LConstantOperand::cast(right)));
+ // Try strength reductions on the multiplication.
+ // All replacement instructions are at most as long as the imul
+ // and have better latency.
+ int constant = ToInteger32(LConstantOperand::cast(right));
+ if (constant == -1) {
+ __ neg(left);
+ } else if (constant == 0) {
+ __ xor_(left, Operand(left));
+ } else if (constant == 2) {
+ __ add(left, Operand(left));
+ } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+ // If we know that the multiplication can't overflow, it's safe to
+ // use instructions that don't set the overflow flag for the
+ // multiplication.
+ switch (constant) {
+ case 1:
+ // Do nothing.
+ break;
+ case 3:
+ __ lea(left, Operand(left, left, times_2, 0));
+ break;
+ case 4:
+ __ shl(left, 2);
+ break;
+ case 5:
+ __ lea(left, Operand(left, left, times_4, 0));
+ break;
+ case 8:
+ __ shl(left, 3);
+ break;
+ case 9:
+ __ lea(left, Operand(left, left, times_8, 0));
+ break;
+ case 16:
+ __ shl(left, 4);
+ break;
+ default:
+ __ imul(left, left, constant);
+ break;
+ }
+ } else {
+ __ imul(left, left, constant);
+ }
} else {
__ imul(left, ToOperand(right));
}
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
@@ -1083,14 +1106,14 @@
Register array = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
}
-void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
+void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
- __ mov(result, FieldOperand(array, PixelArray::kLengthOffset));
+ __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
}
void LCodeGen::DoValueOf(LValueOf* instr) {
Register input = ToRegister(instr->InputAt(0));
@@ -1145,39 +1168,42 @@
}
}
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
- LOperand* left = instr->InputAt(0);
- LOperand* right = instr->InputAt(1);
+ XMMRegister left = ToDoubleRegister(instr->InputAt(0));
+ XMMRegister right = ToDoubleRegister(instr->InputAt(1));
+ XMMRegister result = ToDoubleRegister(instr->result());
// Modulo uses a fixed result register.
- ASSERT(instr->op() == Token::MOD || left->Equals(instr->result()));
+ ASSERT(instr->op() == Token::MOD || left.is(result));
switch (instr->op()) {
case Token::ADD:
- __ addsd(ToDoubleRegister(left), ToDoubleRegister(right));
+ __ addsd(left, right);
break;
case Token::SUB:
- __ subsd(ToDoubleRegister(left), ToDoubleRegister(right));
+ __ subsd(left, right);
break;
case Token::MUL:
- __ mulsd(ToDoubleRegister(left), ToDoubleRegister(right));
+ __ mulsd(left, right);
break;
case Token::DIV:
- __ divsd(ToDoubleRegister(left), ToDoubleRegister(right));
+ __ divsd(left, right);
break;
case Token::MOD: {
// Pass two doubles as arguments on the stack.
__ PrepareCallCFunction(4, eax);
- __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
- __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
- __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
+ __ movdbl(Operand(esp, 0 * kDoubleSize), left);
+ __ movdbl(Operand(esp, 1 * kDoubleSize), right);
+ __ CallCFunction(
+ ExternalReference::double_fp_operation(Token::MOD, isolate()),
+ 4);
// Return value is in st(0) on ia32.
// Store it into the (fixed) result register.
__ sub(Operand(esp), Immediate(kDoubleSize));
__ fstp_d(Operand(esp, 0));
- __ movdbl(ToDoubleRegister(instr->result()), Operand(esp, 0));
+ __ movdbl(result, Operand(esp, 0));
__ add(Operand(esp), Immediate(kDoubleSize));
break;
}
default:
UNREACHABLE();
@@ -1239,31 +1265,31 @@
EmitBranch(true_block, false_block, not_equal);
} else {
ASSERT(r.IsTagged());
Register reg = ToRegister(instr->InputAt(0));
if (instr->hydrogen()->type().IsBoolean()) {
- __ cmp(reg, Factory::true_value());
+ __ cmp(reg, factory()->true_value());
EmitBranch(true_block, false_block, equal);
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
- __ cmp(reg, Factory::undefined_value());
+ __ cmp(reg, factory()->undefined_value());
__ j(equal, false_label);
- __ cmp(reg, Factory::true_value());
+ __ cmp(reg, factory()->true_value());
__ j(equal, true_label);
- __ cmp(reg, Factory::false_value());
+ __ cmp(reg, factory()->false_value());
__ j(equal, false_label);
__ test(reg, Operand(reg));
__ j(equal, false_label);
__ test(reg, Immediate(kSmiTagMask));
__ j(zero, true_label);
// Test for double values. Zero is false.
NearLabel call_stub;
__ cmp(FieldOperand(reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
__ j(not_equal, &call_stub);
__ fldz();
__ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
__ FCmp();
__ j(zero, false_label);
@@ -1289,11 +1315,11 @@
int next_block = GetNextEmittedBlock(current_block_);
if (block != next_block) {
// Perform stack overflow check if this goto needs it before jumping.
if (deferred_stack_check != NULL) {
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, chunk_->GetAssemblyLabel(block));
__ jmp(deferred_stack_check->entry());
deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
} else {
@@ -1382,15 +1408,15 @@
EmitCmpI(left, right);
}
NearLabel done;
Condition cc = TokenToCondition(instr->op(), instr->is_double());
- __ mov(ToRegister(result), Factory::true_value());
+ __ mov(ToRegister(result), factory()->true_value());
__ j(cc, &done);
__ bind(&unordered);
- __ mov(ToRegister(result), Factory::false_value());
+ __ mov(ToRegister(result), factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
@@ -1417,14 +1443,14 @@
Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1));
Register result = ToRegister(instr->result());
__ cmp(left, Operand(right));
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
NearLabel done;
__ j(equal, &done);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
@@ -1443,21 +1469,21 @@
Register result = ToRegister(instr->result());
// TODO(fsc): If the expression is known to be a smi, then it's
// definitely not null. Materialize false.
- __ cmp(reg, Factory::null_value());
+ __ cmp(reg, factory()->null_value());
if (instr->is_strict()) {
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
NearLabel done;
__ j(equal, &done);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
} else {
NearLabel true_value, false_value, done;
__ j(equal, &true_value);
- __ cmp(reg, Factory::undefined_value());
+ __ cmp(reg, factory()->undefined_value());
__ j(equal, &true_value);
__ test(reg, Immediate(kSmiTagMask));
__ j(zero, &false_value);
// Check for undetectable objects by looking in the bit field in
// the map. The object has already been smi checked.
@@ -1465,14 +1491,14 @@
__ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
__ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
__ test(scratch, Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, &true_value);
__ bind(&false_value);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&true_value);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ bind(&done);
}
}
@@ -1483,18 +1509,18 @@
// definitely not null. Jump to the false block.
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
- __ cmp(reg, Factory::null_value());
+ __ cmp(reg, factory()->null_value());
if (instr->is_strict()) {
EmitBranch(true_block, false_block, equal);
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
__ j(equal, true_label);
- __ cmp(reg, Factory::undefined_value());
+ __ cmp(reg, factory()->undefined_value());
__ j(equal, true_label);
__ test(reg, Immediate(kSmiTagMask));
__ j(zero, false_label);
// Check for undetectable objects by looking in the bit field in
// the map. The object has already been smi checked.
@@ -1517,11 +1543,11 @@
ASSERT(!temp1.is(temp2));
__ test(input, Immediate(kSmiTagMask));
__ j(equal, is_not_object);
- __ cmp(input, Factory::null_value());
+ __ cmp(input, isolate()->factory()->null_value());
__ j(equal, is_object);
__ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
// Undetectable objects behave like undefined.
__ movzx_b(temp2, FieldOperand(temp1, Map::kBitFieldOffset));
@@ -1544,15 +1570,15 @@
Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
__ j(true_cond, &is_true);
__ bind(&is_false);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&is_true);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ bind(&done);
}
@@ -1576,14 +1602,14 @@
Operand input = ToOperand(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
__ test(input, Immediate(kSmiTagMask));
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
NearLabel done;
__ j(zero, &done);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
@@ -1625,14 +1651,14 @@
__ test(input, Immediate(kSmiTagMask));
NearLabel done, is_false;
__ j(zero, &is_false);
__ CmpObjectType(input, TestType(instr->hydrogen()), result);
__ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ jmp(&done);
__ bind(&is_false);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
@@ -1650,21 +1676,34 @@
__ CmpObjectType(input, TestType(instr->hydrogen()), temp);
EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
}
+void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
+ Register input = ToRegister(instr->InputAt(0));
+ Register result = ToRegister(instr->result());
+
+ if (FLAG_debug_code) {
+ __ AbortIfNotString(input);
+ }
+
+ __ mov(result, FieldOperand(input, String::kHashFieldOffset));
+ __ IndexFromHash(result, result);
+}
+
+
void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ test(FieldOperand(input, String::kHashFieldOffset),
Immediate(String::kContainsCachedArrayIndexMask));
NearLabel done;
- __ j(not_zero, &done);
- __ mov(result, Factory::false_value());
+ __ j(zero, &done);
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoHasCachedArrayIndexAndBranch(
@@ -1674,11 +1713,11 @@
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
__ test(FieldOperand(input, String::kHashFieldOffset),
Immediate(String::kContainsCachedArrayIndexMask));
- EmitBranch(true_block, false_block, not_equal);
+ EmitBranch(true_block, false_block, equal);
}
// Branches to a label or falls through with the answer in the z flag. Trashes
// the temp registers, but not the input. Only input and temp2 may alias.
@@ -1749,15 +1788,15 @@
EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input);
__ j(not_equal, &is_false);
__ bind(&is_true);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ jmp(&done);
__ bind(&is_false);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
@@ -1801,14 +1840,14 @@
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
NearLabel true_value, done;
__ test(eax, Operand(eax));
__ j(zero, &true_value);
- __ mov(ToRegister(instr->result()), Factory::false_value());
+ __ mov(ToRegister(instr->result()), factory()->false_value());
__ jmp(&done);
__ bind(&true_value);
- __ mov(ToRegister(instr->result()), Factory::true_value());
+ __ mov(ToRegister(instr->result()), factory()->true_value());
__ bind(&done);
}
void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
@@ -1856,31 +1895,31 @@
// instanceof stub.
NearLabel cache_miss;
Register map = ToRegister(instr->TempAt(0));
__ mov(map, FieldOperand(object, HeapObject::kMapOffset));
__ bind(deferred->map_check()); // Label for calculating code patching.
- __ cmp(map, Factory::the_hole_value()); // Patched to cached map.
+ __ cmp(map, factory()->the_hole_value()); // Patched to cached map.
__ j(not_equal, &cache_miss, not_taken);
- __ mov(eax, Factory::the_hole_value()); // Patched to either true or false.
+ __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
__ jmp(&done);
// The inlined call site cache did not match. Check for null and string
// before calling the deferred code.
__ bind(&cache_miss);
// Null is not an instance of anything.
- __ cmp(object, Factory::null_value());
+ __ cmp(object, factory()->null_value());
__ j(equal, &false_result);
// String values are not instances of anything.
Condition is_string = masm_->IsObjectStringType(object, temp, temp);
__ j(is_string, &false_result);
// Go to the deferred code.
__ jmp(deferred->entry());
__ bind(&false_result);
- __ mov(ToRegister(instr->result()), Factory::false_value());
+ __ mov(ToRegister(instr->result()), factory()->false_value());
// Here result has either true or false. Deferred code also produces true or
// false object.
__ bind(deferred->exit());
__ bind(&done);
@@ -1906,20 +1945,13 @@
Register temp = ToRegister(instr->TempAt(0));
ASSERT(temp.is(edi));
__ mov(InstanceofStub::right(), Immediate(instr->function()));
static const int kAdditionalDelta = 16;
int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
- Label before_push_delta;
- __ bind(&before_push_delta);
__ mov(temp, Immediate(delta));
__ StoreToSafepointRegisterSlot(temp, temp);
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- __ call(stub.GetCode(), RelocInfo::CODE_TARGET);
- ASSERT_EQ(kAdditionalDelta,
- masm_->SizeOfCodeGeneratedSince(&before_push_delta));
- RecordSafepointWithRegisters(
- instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
// Put the result value into the eax slot and restore all registers.
__ StoreToSafepointRegisterSlot(eax, eax);
__ PopSafepointRegisters();
}
@@ -1955,14 +1987,14 @@
condition = ReverseCondition(condition);
}
NearLabel true_value, done;
__ test(eax, Operand(eax));
__ j(condition, &true_value);
- __ mov(ToRegister(instr->result()), Factory::false_value());
+ __ mov(ToRegister(instr->result()), factory()->false_value());
__ jmp(&done);
__ bind(&true_value);
- __ mov(ToRegister(instr->result()), Factory::true_value());
+ __ mov(ToRegister(instr->result()), factory()->true_value());
__ bind(&done);
}
void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
@@ -1998,30 +2030,43 @@
__ pop(ebp);
__ Ret((ParameterCount() + 1) * kPointerSize, ecx);
}
-void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
+void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
Register result = ToRegister(instr->result());
__ mov(result, Operand::Cell(instr->hydrogen()->cell()));
if (instr->hydrogen()->check_hole_value()) {
- __ cmp(result, Factory::the_hole_value());
+ __ cmp(result, factory()->the_hole_value());
DeoptimizeIf(equal, instr->environment());
}
}
+void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
+ ASSERT(ToRegister(instr->global_object()).is(eax));
+ ASSERT(ToRegister(instr->result()).is(eax));
+
+ __ mov(ecx, instr->name());
+ RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
+ RelocInfo::CODE_TARGET_CONTEXT;
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, mode, instr);
+}
+
+
void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
Register value = ToRegister(instr->InputAt(0));
Operand cell_operand = Operand::Cell(instr->hydrogen()->cell());
// If the cell we are storing to contains the hole it could have
// been deleted from the property dictionary. In that case, we need
// to update the property details in the property dictionary to mark
// it as no longer deleted. We deoptimize in that case.
if (instr->hydrogen()->check_hole_value()) {
- __ cmp(cell_operand, Factory::the_hole_value());
+ __ cmp(cell_operand, factory()->the_hole_value());
DeoptimizeIf(equal, instr->environment());
}
// Store the value.
__ mov(cell_operand, value);
@@ -2046,28 +2091,91 @@
}
}
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
- Register object = ToRegister(instr->InputAt(0));
+ Register object = ToRegister(instr->object());
Register result = ToRegister(instr->result());
if (instr->hydrogen()->is_in_object()) {
__ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
} else {
__ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
__ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
}
}
+void LCodeGen::EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name) {
+ LookupResult lookup;
+ type->LookupInDescriptors(NULL, *name, &lookup);
+ ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
+ int index = lookup.GetLocalFieldIndexFromMap(*type);
+ int offset = index * kPointerSize;
+ if (index < 0) {
+ // Negative property indices are in-object properties, indexed
+ // from the end of the fixed part of the object.
+ __ mov(result, FieldOperand(object, offset + type->instance_size()));
+ } else {
+ // Non-negative property indices are in the properties array.
+ __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
+ __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+ }
+}
+
+
+void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
+ Register object = ToRegister(instr->object());
+ Register result = ToRegister(instr->result());
+
+ int map_count = instr->hydrogen()->types()->length();
+ Handle<String> name = instr->hydrogen()->name();
+ if (map_count == 0) {
+ ASSERT(instr->hydrogen()->need_generic());
+ __ mov(ecx, name);
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
+ } else {
+ NearLabel done;
+ for (int i = 0; i < map_count - 1; ++i) {
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ NearLabel next;
+ __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ __ j(not_equal, &next);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&next);
+ }
+ Handle<Map> map = instr->hydrogen()->types()->last();
+ __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ if (instr->hydrogen()->need_generic()) {
+ NearLabel generic;
+ __ j(not_equal, &generic);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&generic);
+ __ mov(ecx, name);
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
+ } else {
+ DeoptimizeIf(not_equal, instr->environment());
+ EmitLoadField(result, object, map, name);
+ }
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(eax));
ASSERT(ToRegister(instr->result()).is(eax));
__ mov(ecx, instr->name());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
@@ -2088,11 +2196,11 @@
// Get the prototype or initial map from the function.
__ mov(result,
FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
// Check that the function has a prototype or an initial map.
- __ cmp(Operand(result), Immediate(Factory::the_hole_value()));
+ __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
DeoptimizeIf(equal, instr->environment());
// If the function does not have an initial map, we're done.
NearLabel done;
__ CmpObjectType(result, MAP_TYPE, temp);
@@ -2117,28 +2225,34 @@
Register input = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
NearLabel done;
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(factory()->fixed_array_map()));
__ j(equal, &done);
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::pixel_array_map()));
+ Immediate(factory()->fixed_cow_array_map()));
__ j(equal, &done);
- __ cmp(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::fixed_cow_array_map()));
- __ Check(equal, "Check for fast elements or pixel array failed.");
+ Register temp((result.is(eax)) ? ebx : eax);
+ __ push(temp);
+ __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
+ __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
+ __ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
+ __ cmp(Operand(temp), Immediate(kExternalArrayTypeCount));
+ __ pop(temp);
+ __ Check(below, "Check for fast elements or pixel array failed.");
__ bind(&done);
}
}
-void LCodeGen::DoLoadPixelArrayExternalPointer(
- LLoadPixelArrayExternalPointer* instr) {
+void LCodeGen::DoLoadExternalArrayPointer(
+ LLoadExternalArrayPointer* instr) {
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
- __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
+ __ mov(result, FieldOperand(input,
+ ExternalArray::kExternalPointerOffset));
}
void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
Register arguments = ToRegister(instr->arguments());
@@ -2166,32 +2280,65 @@
key,
times_pointer_size,
FixedArray::kHeaderSize));
// Check for the hole value.
- __ cmp(result, Factory::the_hole_value());
+ __ cmp(result, factory()->the_hole_value());
DeoptimizeIf(equal, instr->environment());
}
-void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
+void LCodeGen::DoLoadKeyedSpecializedArrayElement(
+ LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
- Register result = ToRegister(instr->result());
- ASSERT(result.is(external_pointer));
-
- // Load the result.
- __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
+ ExternalArrayType array_type = instr->array_type();
+ if (array_type == kExternalFloatArray) {
+ XMMRegister result(ToDoubleRegister(instr->result()));
+ __ movss(result, Operand(external_pointer, key, times_4, 0));
+ __ cvtss2sd(result, result);
+ } else {
+ Register result(ToRegister(instr->result()));
+ switch (array_type) {
+ case kExternalByteArray:
+ __ movsx_b(result, Operand(external_pointer, key, times_1, 0));
+ break;
+ case kExternalUnsignedByteArray:
+ case kExternalPixelArray:
+ __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
+ break;
+ case kExternalShortArray:
+ __ movsx_w(result, Operand(external_pointer, key, times_2, 0));
+ break;
+ case kExternalUnsignedShortArray:
+ __ movzx_w(result, Operand(external_pointer, key, times_2, 0));
+ break;
+ case kExternalIntArray:
+ __ mov(result, Operand(external_pointer, key, times_4, 0));
+ break;
+ case kExternalUnsignedIntArray:
+ __ mov(result, Operand(external_pointer, key, times_4, 0));
+ __ test(result, Operand(result));
+ // TODO(danno): we could be more clever here, perhaps having a special
+ // version of the stub that detects if the overflow case actually
+ // happens, and generate code that returns a double rather than int.
+ DeoptimizeIf(negative, instr->environment());
+ break;
+ case kExternalFloatArray:
+ UNREACHABLE();
+ break;
+ }
+ }
}
void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx));
ASSERT(ToRegister(instr->key()).is(eax));
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
@@ -2252,13 +2399,13 @@
ASSERT(ToRegister(instr->result()).is(eax));
// If the receiver is null or undefined, we have to pass the global object
// as a receiver.
NearLabel global_object, receiver_ok;
- __ cmp(receiver, Factory::null_value());
+ __ cmp(receiver, factory()->null_value());
__ j(equal, &global_object);
- __ cmp(receiver, Factory::undefined_value());
+ __ cmp(receiver, factory()->undefined_value());
__ j(equal, &global_object);
// The receiver should be a JS object.
__ test(receiver, Immediate(kSmiTagMask));
DeoptimizeIf(equal, instr->environment());
@@ -2301,12 +2448,11 @@
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env);
SafepointGenerator safepoint_generator(this,
pointers,
- env->deoptimization_index(),
- true);
+ env->deoptimization_index());
v8::internal::ParameterCount actual(eax);
__ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
}
@@ -2351,11 +2497,11 @@
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr) {
// Change context if needed.
bool change_context =
- (graph()->info()->closure()->context() != function->context()) ||
+ (info()->closure()->context() != function->context()) ||
scope()->contains_with() ||
(scope()->num_heap_slots() > 0);
if (change_context) {
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
} else {
@@ -2370,15 +2516,14 @@
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
// Invoke function.
- if (*function == *graph()->info()->closure()) {
+ if (*function == *info()->closure()) {
__ CallSelf();
} else {
__ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
- EnsureRelocSpaceForDeoptimization();
}
// Setup deoptimization.
RegisterLazyDeoptimization(instr);
}
@@ -2392,11 +2537,11 @@
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
Register input_reg = ToRegister(instr->InputAt(0));
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
DeoptimizeIf(not_equal, instr->environment());
Label done;
Register tmp = input_reg.is(eax) ? ecx : eax;
Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
@@ -2573,25 +2718,28 @@
void LCodeGen::DoPower(LPower* instr) {
LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1);
DoubleRegister result_reg = ToDoubleRegister(instr->result());
Representation exponent_type = instr->hydrogen()->right()->representation();
+
if (exponent_type.IsDouble()) {
// It is safe to use ebx directly since the instruction is marked
// as a call.
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
- __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
+ 4);
} else if (exponent_type.IsInteger32()) {
// It is safe to use ebx directly since the instruction is marked
// as a call.
ASSERT(!ToRegister(right).is(ebx));
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
- __ CallCFunction(ExternalReference::power_double_int_function(), 4);
+ __ CallCFunction(ExternalReference::power_double_int_function(isolate()),
+ 4);
} else {
ASSERT(exponent_type.IsTagged());
CpuFeatures::Scope scope(SSE2);
Register right_reg = ToRegister(right);
@@ -2612,11 +2760,12 @@
__ bind(&call);
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
- __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
+ 4);
}
// Return value is in st(0) on ia32.
// Store it into the (fixed) result register.
__ sub(Operand(esp), Immediate(kDoubleSize));
@@ -2687,21 +2836,23 @@
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->key()).is(ecx));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->
+ ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoCallNamed(LCallNamed* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->
+ ComputeCallInitialize(arity, NOT_IN_LOOP);
__ mov(ecx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2719,11 +2870,12 @@
void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->
+ ComputeCallInitialize(arity, NOT_IN_LOOP);
__ mov(ecx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
}
@@ -2737,11 +2889,11 @@
void LCodeGen::DoCallNew(LCallNew* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->constructor()).is(edi));
ASSERT(ToRegister(instr->result()).is(eax));
- Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
__ Set(eax, Immediate(instr->arity()));
CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
}
@@ -2784,37 +2936,69 @@
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx));
ASSERT(ToRegister(instr->value()).is(eax));
__ mov(ecx, instr->name());
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ Handle<Code> ic = info_->is_strict()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
__ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
DeoptimizeIf(above_equal, instr->environment());
}
-void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
+void LCodeGen::DoStoreKeyedSpecializedArrayElement(
+ LStoreKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
- Register value = ToRegister(instr->value());
- ASSERT(ToRegister(instr->TempAt(0)).is(eax));
-
- __ mov(eax, value);
- { // Clamp the value to [0..255].
- NearLabel done;
- __ test(eax, Immediate(0xFFFFFF00));
- __ j(zero, &done);
- __ setcc(negative, eax); // 1 if negative, 0 if positive.
- __ dec_b(eax); // 0 if negative, 255 if positive.
- __ bind(&done);
+ ExternalArrayType array_type = instr->array_type();
+ if (array_type == kExternalFloatArray) {
+ __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
+ __ movss(Operand(external_pointer, key, times_4, 0), xmm0);
+ } else {
+ Register value = ToRegister(instr->value());
+ switch (array_type) {
+ case kExternalPixelArray: {
+ // Clamp the value to [0..255].
+ Register temp = ToRegister(instr->TempAt(0));
+ // The dec_b below requires that the clamped value is in a byte
+ // register. eax is an arbitrary choice to satisfy this requirement, we
+ // hinted the register allocator to give us eax when building the
+ // instruction.
+ ASSERT(temp.is(eax));
+ __ mov(temp, ToRegister(instr->value()));
+ NearLabel done;
+ __ test(temp, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, temp); // 1 if negative, 0 if positive.
+ __ dec_b(temp); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ __ mov_b(Operand(external_pointer, key, times_1, 0), temp);
+ break;
+ }
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ __ mov_b(Operand(external_pointer, key, times_1, 0), value);
+ break;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ __ mov_w(Operand(external_pointer, key, times_2, 0), value);
+ break;
+ case kExternalIntArray:
+ case kExternalUnsignedIntArray:
+ __ mov(Operand(external_pointer, key, times_4, 0), value);
+ break;
+ case kExternalFloatArray:
+ UNREACHABLE();
+ break;
+ }
}
- __ mov_b(Operand(external_pointer, key, times_1, 0), eax);
}
void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
Register value = ToRegister(instr->value());
@@ -2852,11 +3036,13 @@
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx));
ASSERT(ToRegister(instr->key()).is(ecx));
ASSERT(ToRegister(instr->value()).is(eax));
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = info_->is_strict()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
@@ -2912,11 +3098,11 @@
// Check whether the right hand side is the empty string (i.e. if
// this is really a flat string in a cons string). If that is not
// the case we would rather go to the runtime system now to flatten
// the string.
__ cmp(FieldOperand(string, ConsString::kSecondOffset),
- Immediate(Factory::empty_string()));
+ Immediate(factory()->empty_string()));
__ j(not_equal, deferred->entry());
// Get the first of the two strings and load its instance type.
__ mov(string, FieldOperand(string, ConsString::kFirstOffset));
__ mov(result, FieldOperand(string, HeapObject::kMapOffset));
__ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
@@ -2997,10 +3183,60 @@
__ StoreToSafepointRegisterSlot(result, eax);
__ PopSafepointRegisters();
}
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+ class DeferredStringCharFromCode: public LDeferredCode {
+ public:
+ DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
+ private:
+ LStringCharFromCode* instr_;
+ };
+
+ DeferredStringCharFromCode* deferred =
+ new DeferredStringCharFromCode(this, instr);
+
+ ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+ ASSERT(!char_code.is(result));
+
+ __ cmp(char_code, String::kMaxAsciiCharCode);
+ __ j(above, deferred->entry());
+ __ Set(result, Immediate(factory()->single_character_string_cache()));
+ __ mov(result, FieldOperand(result,
+ char_code, times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ cmp(result, factory()->undefined_value());
+ __ j(equal, deferred->entry());
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+
+ // TODO(3095996): Get rid of this. For now, we need to make the
+ // result register contain a valid pointer because it is already
+ // contained in the register pointer map.
+ __ Set(result, Immediate(0));
+
+ __ PushSafepointRegisters();
+ __ SmiTag(char_code);
+ __ push(char_code);
+ __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
+ __ StoreToSafepointRegisterSlot(result, eax);
+ __ PopSafepointRegisters();
+}
+
+
void LCodeGen::DoStringLength(LStringLength* instr) {
Register string = ToRegister(instr->string());
Register result = ToRegister(instr->result());
__ mov(result, FieldOperand(string, String::kLengthOffset));
}
@@ -3149,21 +3385,19 @@
__ test(input_reg, Immediate(kSmiTagMask));
__ j(zero, &load_smi, not_taken);
// Heap number map check.
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
__ j(equal, &heap_number);
- __ cmp(input_reg, Factory::undefined_value());
+ __ cmp(input_reg, factory()->undefined_value());
DeoptimizeIf(not_equal, env);
// Convert undefined to NaN.
- __ push(input_reg);
- __ mov(input_reg, Factory::nan_value());
- __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
- __ pop(input_reg);
+ ExternalReference nan = ExternalReference::address_of_nan();
+ __ movdbl(result_reg, Operand::StaticVariable(nan));
__ jmp(&done);
// Heap number to XMM conversion.
__ bind(&heap_number);
__ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
@@ -3192,17 +3426,17 @@
NearLabel done, heap_number;
Register input_reg = ToRegister(instr->InputAt(0));
// Heap number map check.
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
if (instr->truncating()) {
__ j(equal, &heap_number);
// Check for undefined. Undefined is converted to zero for truncating
// conversions.
- __ cmp(input_reg, Factory::undefined_value());
+ __ cmp(input_reg, factory()->undefined_value());
DeoptimizeIf(not_equal, instr->environment());
__ mov(input_reg, 0);
__ jmp(&done);
__ bind(&heap_number);
@@ -3419,16 +3653,22 @@
}
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
LOperand* input = instr->InputAt(0);
- ASSERT(input->IsRegister());
__ test(ToRegister(input), Immediate(kSmiTagMask));
- DeoptimizeIf(instr->condition(), instr->environment());
+ DeoptimizeIf(not_zero, instr->environment());
}
+void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
+ LOperand* input = instr->InputAt(0);
+ __ test(ToRegister(input), Immediate(kSmiTagMask));
+ DeoptimizeIf(zero, instr->environment());
+}
+
+
void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
Register input = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0));
InstanceType first = instr->hydrogen()->first();
InstanceType last = instr->hydrogen()->last();
@@ -3475,13 +3715,13 @@
DeoptimizeIf(not_equal, instr->environment());
}
void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
- if (Heap::InNewSpace(*object)) {
+ if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
- Factory::NewJSGlobalPropertyCell(object);
+ isolate()->factory()->NewJSGlobalPropertyCell(object);
__ mov(result, Operand::Cell(cell));
} else {
__ mov(result, object);
}
}
@@ -3547,21 +3787,34 @@
// Setup the parameters to the stub/runtime call.
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
__ push(Immediate(instr->hydrogen()->constant_properties()));
- __ push(Immediate(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
+ int flags = instr->hydrogen()->fast_elements()
+ ? ObjectLiteral::kFastElements
+ : ObjectLiteral::kNoFlags;
+ flags |= instr->hydrogen()->has_function()
+ ? ObjectLiteral::kHasFunction
+ : ObjectLiteral::kNoFlags;
+ __ push(Immediate(Smi::FromInt(flags)));
// Pick the right runtime function to call.
if (instr->hydrogen()->depth() > 1) {
CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
} else {
CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
}
}
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+ ASSERT(ToRegister(instr->InputAt(0)).is(eax));
+ __ push(eax);
+ CallRuntime(Runtime::kToFastProperties, 1, instr);
+}
+
+
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
NearLabel materialized;
// Registers will be used as follows:
// edi = JS function.
// ecx = literals array.
@@ -3570,11 +3823,11 @@
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
int literal_offset = FixedArray::kHeaderSize +
instr->hydrogen()->literal_index() * kPointerSize;
__ mov(ebx, FieldOperand(ecx, literal_offset));
- __ cmp(ebx, Factory::undefined_value());
+ __ cmp(ebx, factory()->undefined_value());
__ j(not_equal, &materialized);
// Create regexp literal using runtime function
// Result will be in eax.
__ push(ecx);
@@ -3615,20 +3868,21 @@
void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (shared_info->num_literals() == 0 && !pretenure) {
- FastNewClosureStub stub;
+ if (!pretenure && shared_info->num_literals() == 0) {
+ FastNewClosureStub stub(
+ shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
__ push(Immediate(shared_info));
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
} else {
__ push(Operand(ebp, StandardFrameConstants::kContextOffset));
__ push(Immediate(shared_info));
__ push(Immediate(pretenure
- ? Factory::true_value()
- : Factory::false_value()));
+ ? factory()->true_value()
+ : factory()->false_value()));
CallRuntime(Runtime::kNewClosure, 3, instr, false);
}
}
@@ -3654,15 +3908,15 @@
&false_label,
input,
instr->type_literal());
__ j(final_branch_condition, &true_label);
__ bind(&false_label);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&true_label);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ bind(&done);
}
@@ -3685,70 +3939,61 @@
Condition LCodeGen::EmitTypeofIs(Label* true_label,
Label* false_label,
Register input,
Handle<String> type_name) {
Condition final_branch_condition = no_condition;
- if (type_name->Equals(Heap::number_symbol())) {
- __ test(input, Immediate(kSmiTagMask));
- __ j(zero, true_label);
+ if (type_name->Equals(heap()->number_symbol())) {
+ __ JumpIfSmi(input, true_label);
__ cmp(FieldOperand(input, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
final_branch_condition = equal;
- } else if (type_name->Equals(Heap::string_symbol())) {
- __ test(input, Immediate(kSmiTagMask));
- __ j(zero, false_label);
- __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
+ } else if (type_name->Equals(heap()->string_symbol())) {
+ __ JumpIfSmi(input, false_label);
+ __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
+ __ j(above_equal, false_label);
__ test_b(FieldOperand(input, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
- __ j(not_zero, false_label);
- __ CmpInstanceType(input, FIRST_NONSTRING_TYPE);
- final_branch_condition = below;
+ final_branch_condition = zero;
- } else if (type_name->Equals(Heap::boolean_symbol())) {
- __ cmp(input, Factory::true_value());
+ } else if (type_name->Equals(heap()->boolean_symbol())) {
+ __ cmp(input, factory()->true_value());
__ j(equal, true_label);
- __ cmp(input, Factory::false_value());
+ __ cmp(input, factory()->false_value());
final_branch_condition = equal;
- } else if (type_name->Equals(Heap::undefined_symbol())) {
- __ cmp(input, Factory::undefined_value());
+ } else if (type_name->Equals(heap()->undefined_symbol())) {
+ __ cmp(input, factory()->undefined_value());
__ j(equal, true_label);
- __ test(input, Immediate(kSmiTagMask));
- __ j(zero, false_label);
+ __ JumpIfSmi(input, false_label);
// Check for undetectable objects => true.
__ mov(input, FieldOperand(input, HeapObject::kMapOffset));
__ test_b(FieldOperand(input, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
final_branch_condition = not_zero;
- } else if (type_name->Equals(Heap::function_symbol())) {
- __ test(input, Immediate(kSmiTagMask));
- __ j(zero, false_label);
+ } else if (type_name->Equals(heap()->function_symbol())) {
+ __ JumpIfSmi(input, false_label);
__ CmpObjectType(input, JS_FUNCTION_TYPE, input);
__ j(equal, true_label);
// Regular expressions => 'function' (they are callable).
__ CmpInstanceType(input, JS_REGEXP_TYPE);
final_branch_condition = equal;
- } else if (type_name->Equals(Heap::object_symbol())) {
- __ test(input, Immediate(kSmiTagMask));
- __ j(zero, false_label);
- __ cmp(input, Factory::null_value());
+ } else if (type_name->Equals(heap()->object_symbol())) {
+ __ JumpIfSmi(input, false_label);
+ __ cmp(input, factory()->null_value());
__ j(equal, true_label);
// Regular expressions => 'function', not 'object'.
- __ CmpObjectType(input, JS_REGEXP_TYPE, input);
- __ j(equal, false_label);
+ __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input);
+ __ j(below, false_label);
+ __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE);
+ __ j(above_equal, false_label);
// Check for undetectable objects => false.
__ test_b(FieldOperand(input, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
- __ j(not_zero, false_label);
- // Check for JS objects => true.
- __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE);
- __ j(below, false_label);
- __ CmpInstanceType(input, LAST_JS_OBJECT_TYPE);
- final_branch_condition = below_equal;
+ final_branch_condition = zero;
} else {
final_branch_condition = not_equal;
__ jmp(false_label);
// A dead branch instruction will be generated after this point.
@@ -3765,15 +4010,15 @@
NearLabel done;
EmitIsConstructCall(result);
__ j(equal, &true_label);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&true_label);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ bind(&done);
}
@@ -3833,21 +4078,21 @@
// Create safepoint generator that will also ensure enough space in the
// reloc info for patching in deoptimization (since this is invoking a
// builtin)
SafepointGenerator safepoint_generator(this,
pointers,
- env->deoptimization_index(),
- true);
+ env->deoptimization_index());
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ push(Immediate(Smi::FromInt(strict_mode_flag())));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
}
void LCodeGen::DoStackCheck(LStackCheck* instr) {
// Perform stack overflow check.
NearLabel done;
- ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &done);
StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);