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);