Index: src/ia32/full-codegen-ia32.cc |
=================================================================== |
--- src/ia32/full-codegen-ia32.cc (revision 9531) |
+++ src/ia32/full-codegen-ia32.cc (working copy) |
@@ -138,7 +138,7 @@ |
// function calls. |
if (info->is_strict_mode() || info->is_native()) { |
Label ok; |
- __ test(ecx, Operand(ecx)); |
+ __ test(ecx, ecx); |
__ j(zero, &ok, Label::kNear); |
// +1 for return address. |
int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; |
@@ -147,6 +147,11 @@ |
__ bind(&ok); |
} |
+ // Open a frame scope to indicate that there is a frame on the stack. The |
+ // MANUAL indicates that the scope shouldn't actually generate code to set up |
+ // the frame (that is done below). |
+ FrameScope frame_scope(masm_, StackFrame::MANUAL); |
+ |
__ push(ebp); // Caller's frame pointer. |
__ mov(ebp, esp); |
__ push(esi); // Callee's context. |
@@ -200,11 +205,12 @@ |
// Store it in the context. |
int context_offset = Context::SlotOffset(var->index()); |
__ mov(Operand(esi, context_offset), eax); |
- // Update the write barrier. This clobbers all involved |
- // registers, so we have use a third register to avoid |
- // clobbering esi. |
- __ mov(ecx, esi); |
- __ RecordWrite(ecx, context_offset, eax, ebx); |
+ // Update the write barrier. This clobbers eax and ebx. |
+ __ RecordWriteContextSlot(esi, |
+ context_offset, |
+ eax, |
+ ebx, |
+ kDontSaveFPRegs); |
} |
} |
} |
@@ -365,10 +371,10 @@ |
void FullCodeGenerator::verify_stack_height() { |
ASSERT(FLAG_verify_stack_height); |
- __ sub(Operand(ebp), Immediate(kPointerSize * stack_height())); |
- __ cmp(ebp, Operand(esp)); |
+ __ sub(ebp, Immediate(kPointerSize * stack_height())); |
+ __ cmp(ebp, esp); |
__ Assert(equal, "Full codegen stack height not as expected."); |
- __ add(Operand(ebp), Immediate(kPointerSize * stack_height())); |
+ __ add(ebp, Immediate(kPointerSize * stack_height())); |
} |
@@ -597,7 +603,7 @@ |
ToBooleanStub stub(result_register()); |
__ push(result_register()); |
__ CallStub(&stub, condition->test_id()); |
- __ test(result_register(), Operand(result_register())); |
+ __ test(result_register(), result_register()); |
// The stub returns nonzero for true. |
Split(not_zero, if_true, if_false, fall_through); |
} |
@@ -661,11 +667,12 @@ |
ASSERT(!scratch1.is(src)); |
MemOperand location = VarOperand(var, scratch0); |
__ mov(location, src); |
+ |
// Emit the write barrier code if the location is in the heap. |
if (var->IsContextSlot()) { |
int offset = Context::SlotOffset(var->index()); |
ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi)); |
- __ RecordWrite(scratch0, offset, src, scratch1); |
+ __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs); |
} |
} |
@@ -738,9 +745,14 @@ |
Comment cmnt(masm_, "[ Declaration"); |
VisitForAccumulatorValue(function); |
__ mov(ContextOperand(esi, variable->index()), result_register()); |
- int offset = Context::SlotOffset(variable->index()); |
- __ mov(ebx, esi); |
- __ RecordWrite(ebx, offset, result_register(), ecx); |
+ // We know that we have written a function, which is not a smi. |
+ __ RecordWriteContextSlot(esi, |
+ Context::SlotOffset(variable->index()), |
+ result_register(), |
+ ecx, |
+ kDontSaveFPRegs, |
+ EMIT_REMEMBERED_SET, |
+ OMIT_SMI_CHECK); |
PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
} else if (mode == Variable::CONST || mode == Variable::LET) { |
Comment cmnt(masm_, "[ Declaration"); |
@@ -835,10 +847,10 @@ |
if (inline_smi_code) { |
Label slow_case; |
__ mov(ecx, edx); |
- __ or_(ecx, Operand(eax)); |
+ __ or_(ecx, eax); |
patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
- __ cmp(edx, Operand(eax)); |
+ __ cmp(edx, eax); |
__ j(not_equal, &next_test); |
__ Drop(1); // Switch value is no longer needed. |
__ jmp(clause->body_target()); |
@@ -850,7 +862,7 @@ |
Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
__ call(ic, RelocInfo::CODE_TARGET, clause->CompareId()); |
patch_site.EmitPatchInfo(); |
- __ test(eax, Operand(eax)); |
+ __ test(eax, eax); |
__ j(not_equal, &next_test); |
__ Drop(1); // Switch value is no longer needed. |
__ jmp(clause->body_target()); |
@@ -939,7 +951,7 @@ |
// For all objects but the receiver, check that the cache is empty. |
Label check_prototype; |
- __ cmp(ecx, Operand(eax)); |
+ __ cmp(ecx, eax); |
__ j(equal, &check_prototype, Label::kNear); |
__ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
__ cmp(edx, isolate()->factory()->empty_fixed_array()); |
@@ -1021,9 +1033,9 @@ |
__ push(ecx); // Enumerable. |
__ push(ebx); // Current entry. |
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
- __ test(eax, Operand(eax)); |
+ __ test(eax, eax); |
__ j(equal, loop_statement.continue_label()); |
- __ mov(ebx, Operand(eax)); |
+ __ mov(ebx, eax); |
// Update the 'each' property or variable from the possibly filtered |
// entry in register ebx. |
@@ -1047,7 +1059,7 @@ |
// Remove the pointers stored on the stack. |
__ bind(loop_statement.break_label()); |
- __ add(Operand(esp), Immediate(5 * kPointerSize)); |
+ __ add(esp, Immediate(5 * kPointerSize)); |
decrement_stack_height(ForIn::kElementCount); |
// Exit and decrement the loop depth. |
@@ -1480,8 +1492,20 @@ |
int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
__ mov(FieldOperand(ebx, offset), result_register()); |
+ Label no_map_change; |
+ __ JumpIfSmi(result_register(), &no_map_change); |
// Update the write barrier for the array store. |
- __ RecordWrite(ebx, offset, result_register(), ecx); |
+ __ RecordWriteField(ebx, offset, result_register(), ecx, |
+ kDontSaveFPRegs, |
+ EMIT_REMEMBERED_SET, |
+ OMIT_SMI_CHECK); |
+ if (FLAG_smi_only_arrays) { |
+ __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset)); |
+ __ CheckFastSmiOnlyElements(edi, &no_map_change, Label::kNear); |
+ __ push(Operand(esp, 0)); |
+ __ CallRuntime(Runtime::kNonSmiElementStored, 1); |
+ } |
+ __ bind(&no_map_change); |
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
} |
@@ -1641,7 +1665,7 @@ |
__ pop(edx); |
decrement_stack_height(); |
__ mov(ecx, eax); |
- __ or_(eax, Operand(edx)); |
+ __ or_(eax, edx); |
JumpPatchSite patch_site(masm_); |
patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); |
@@ -1691,32 +1715,32 @@ |
break; |
} |
case Token::ADD: |
- __ add(eax, Operand(ecx)); |
+ __ add(eax, ecx); |
__ j(overflow, &stub_call); |
break; |
case Token::SUB: |
- __ sub(eax, Operand(ecx)); |
+ __ sub(eax, ecx); |
__ j(overflow, &stub_call); |
break; |
case Token::MUL: { |
__ SmiUntag(eax); |
- __ imul(eax, Operand(ecx)); |
+ __ imul(eax, ecx); |
__ j(overflow, &stub_call); |
- __ test(eax, Operand(eax)); |
+ __ test(eax, eax); |
__ j(not_zero, &done, Label::kNear); |
__ mov(ebx, edx); |
- __ or_(ebx, Operand(ecx)); |
+ __ or_(ebx, ecx); |
__ j(negative, &stub_call); |
break; |
} |
case Token::BIT_OR: |
- __ or_(eax, Operand(ecx)); |
+ __ or_(eax, ecx); |
break; |
case Token::BIT_AND: |
- __ and_(eax, Operand(ecx)); |
+ __ and_(eax, ecx); |
break; |
case Token::BIT_XOR: |
- __ xor_(eax, Operand(ecx)); |
+ __ xor_(eax, ecx); |
break; |
default: |
UNREACHABLE(); |
@@ -1859,7 +1883,8 @@ |
__ mov(location, eax); |
if (var->IsContextSlot()) { |
__ mov(edx, eax); |
- __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx); |
+ int offset = Context::SlotOffset(var->index()); |
+ __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
} |
} |
@@ -1877,7 +1902,8 @@ |
__ mov(location, eax); |
if (var->IsContextSlot()) { |
__ mov(edx, eax); |
- __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx); |
+ int offset = Context::SlotOffset(var->index()); |
+ __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
} |
} else { |
ASSERT(var->IsLookupSlot()); |
@@ -2069,8 +2095,29 @@ |
} |
// Record source position for debugger. |
SetSourcePosition(expr->position()); |
+ |
+ // Record call targets in unoptimized code, but not in the snapshot. |
+ bool record_call_target = !Serializer::enabled(); |
+ if (record_call_target) { |
+ flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); |
+ } |
CallFunctionStub stub(arg_count, flags); |
__ CallStub(&stub); |
+ if (record_call_target) { |
+ // There is a one element cache in the instruction stream. |
+#ifdef DEBUG |
+ int return_site_offset = masm()->pc_offset(); |
+#endif |
+ Handle<Object> uninitialized = |
+ CallFunctionStub::UninitializedSentinel(isolate()); |
+ Handle<JSGlobalPropertyCell> cell = |
+ isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); |
+ __ test(eax, Immediate(cell)); |
+ // Patching code in the stub assumes the opcode is 1 byte and there is |
+ // word for a pointer in the operand. |
+ ASSERT(masm()->pc_offset() - return_site_offset >= 1 + kPointerSize); |
+ } |
+ |
RecordJSReturnSite(expr); |
// Restore context register. |
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
@@ -2438,9 +2485,9 @@ |
STATIC_ASSERT(kPointerSize == 4); |
__ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); |
// Calculate location of the first key name. |
- __ add(Operand(ebx), |
- Immediate(FixedArray::kHeaderSize + |
- DescriptorArray::kFirstIndex * kPointerSize)); |
+ __ add(ebx, |
+ Immediate(FixedArray::kHeaderSize + |
+ DescriptorArray::kFirstIndex * kPointerSize)); |
// Loop through all the keys in the descriptor array. If one of these is the |
// symbol valueOf the result is false. |
Label entry, loop; |
@@ -2449,9 +2496,9 @@ |
__ mov(edx, FieldOperand(ebx, 0)); |
__ cmp(edx, FACTORY->value_of_symbol()); |
__ j(equal, if_false); |
- __ add(Operand(ebx), Immediate(kPointerSize)); |
+ __ add(ebx, Immediate(kPointerSize)); |
__ bind(&entry); |
- __ cmp(ebx, Operand(ecx)); |
+ __ cmp(ebx, ecx); |
__ j(not_equal, &loop); |
// Reload map as register ebx was used as temporary above. |
@@ -2591,7 +2638,7 @@ |
__ pop(ebx); |
decrement_stack_height(); |
- __ cmp(eax, Operand(ebx)); |
+ __ cmp(eax, ebx); |
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
Split(equal, if_true, if_false, fall_through); |
@@ -2647,20 +2694,24 @@ |
// Check that the object is a JS object but take special care of JS |
// functions to make sure they have 'Function' as their class. |
+ // Assume that there are only two callable types, and one of them is at |
+ // either end of the type range for JS object types. Saves extra comparisons. |
+ STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax); |
// Map is now in eax. |
__ j(below, &null); |
+ STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
+ FIRST_SPEC_OBJECT_TYPE + 1); |
+ __ j(equal, &function); |
- // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and |
- // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after |
- // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. |
- STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
- STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == |
- LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); |
- __ CmpInstanceType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE); |
- __ j(above_equal, &function); |
+ __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE); |
+ STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
+ LAST_SPEC_OBJECT_TYPE - 1); |
+ __ j(equal, &function); |
+ // Assume that there is no larger type. |
+ STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); |
- // Check if the constructor in the map is a function. |
+ // Check if the constructor in the map is a JS function. |
__ mov(eax, FieldOperand(eax, Map::kConstructorOffset)); |
__ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
__ j(not_equal, &non_function_constructor); |
@@ -2741,8 +2792,8 @@ |
if (CpuFeatures::IsSupported(SSE2)) { |
CpuFeatures::Scope fscope(SSE2); |
__ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
- __ movd(xmm1, Operand(ebx)); |
- __ movd(xmm0, Operand(eax)); |
+ __ movd(xmm1, ebx); |
+ __ movd(xmm0, eax); |
__ cvtss2sd(xmm1, xmm1); |
__ xorps(xmm0, xmm1); |
__ subsd(xmm0, xmm1); |
@@ -2843,10 +2894,11 @@ |
// Store the value. |
__ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); |
+ |
// Update the write barrier. Save the value as it will be |
// overwritten by the write barrier code and is needed afterward. |
__ mov(edx, eax); |
- __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx); |
+ __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs); |
__ bind(&done); |
context()->Plug(eax); |
@@ -3119,14 +3171,14 @@ |
__ mov(index_1, Operand(esp, 1 * kPointerSize)); |
__ mov(index_2, Operand(esp, 0)); |
__ mov(temp, index_1); |
- __ or_(temp, Operand(index_2)); |
+ __ or_(temp, index_2); |
__ JumpIfNotSmi(temp, &slow_case); |
// Check that both indices are valid. |
__ mov(temp, FieldOperand(object, JSArray::kLengthOffset)); |
- __ cmp(temp, Operand(index_1)); |
+ __ cmp(temp, index_1); |
__ j(below_equal, &slow_case); |
- __ cmp(temp, Operand(index_2)); |
+ __ cmp(temp, index_2); |
__ j(below_equal, &slow_case); |
// Bring addresses into index1 and index2. |
@@ -3139,16 +3191,35 @@ |
__ mov(Operand(index_2, 0), object); |
__ mov(Operand(index_1, 0), temp); |
- Label new_space; |
- __ InNewSpace(elements, temp, equal, &new_space); |
+ Label no_remembered_set; |
+ __ CheckPageFlag(elements, |
+ temp, |
+ 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
+ not_zero, |
+ &no_remembered_set, |
+ Label::kNear); |
+ // Possible optimization: do a check that both values are Smis |
+ // (or them and test against Smi mask.) |
- __ mov(object, elements); |
- __ RecordWriteHelper(object, index_1, temp); |
- __ RecordWriteHelper(elements, index_2, temp); |
+ // We are swapping two objects in an array and the incremental marker never |
+ // pauses in the middle of scanning a single object. Therefore the |
+ // incremental marker is not disturbed, so we don't need to call the |
+ // RecordWrite stub that notifies the incremental marker. |
+ __ RememberedSetHelper(elements, |
+ index_1, |
+ temp, |
+ kDontSaveFPRegs, |
+ MacroAssembler::kFallThroughAtEnd); |
+ __ RememberedSetHelper(elements, |
+ index_2, |
+ temp, |
+ kDontSaveFPRegs, |
+ MacroAssembler::kFallThroughAtEnd); |
- __ bind(&new_space); |
+ __ bind(&no_remembered_set); |
+ |
// We are done. Drop elements from the stack, and return undefined. |
- __ add(Operand(esp), Immediate(3 * kPointerSize)); |
+ __ add(esp, Immediate(3 * kPointerSize)); |
__ mov(eax, isolate()->factory()->undefined_value()); |
__ jmp(&done); |
@@ -3221,11 +3292,11 @@ |
__ pop(left); |
Label done, fail, ok; |
- __ cmp(left, Operand(right)); |
+ __ cmp(left, right); |
__ j(equal, &ok); |
// Fail if either is a non-HeapObject. |
__ mov(tmp, left); |
- __ and_(Operand(tmp), right); |
+ __ and_(tmp, right); |
__ JumpIfSmi(tmp, &fail); |
__ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); |
__ CmpInstanceType(tmp, JS_REGEXP_TYPE); |
@@ -3316,7 +3387,7 @@ |
Operand separator_operand = Operand(esp, 2 * kPointerSize); |
Operand result_operand = Operand(esp, 1 * kPointerSize); |
Operand array_length_operand = Operand(esp, 0); |
- __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
+ __ sub(esp, Immediate(2 * kPointerSize)); |
__ cld(); |
// Check that the array is a JSArray |
__ JumpIfSmi(array, &bailout); |
@@ -3352,7 +3423,7 @@ |
// Live loop registers: index, array_length, string, |
// scratch, string_length, elements. |
if (FLAG_debug_code) { |
- __ cmp(index, Operand(array_length)); |
+ __ cmp(index, array_length); |
__ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); |
} |
__ bind(&loop); |
@@ -3370,8 +3441,8 @@ |
__ add(string_length, |
FieldOperand(string, SeqAsciiString::kLengthOffset)); |
__ j(overflow, &bailout); |
- __ add(Operand(index), Immediate(1)); |
- __ cmp(index, Operand(array_length)); |
+ __ add(index, Immediate(1)); |
+ __ cmp(index, array_length); |
__ j(less, &loop); |
// If array_length is 1, return elements[0], a string. |
@@ -3405,10 +3476,10 @@ |
// to string_length. |
__ mov(scratch, separator_operand); |
__ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); |
- __ sub(string_length, Operand(scratch)); // May be negative, temporarily. |
+ __ sub(string_length, scratch); // May be negative, temporarily. |
__ imul(scratch, array_length_operand); |
__ j(overflow, &bailout); |
- __ add(string_length, Operand(scratch)); |
+ __ add(string_length, scratch); |
__ j(overflow, &bailout); |
__ shr(string_length, 1); |
@@ -3449,7 +3520,7 @@ |
__ lea(string, |
FieldOperand(string, SeqAsciiString::kHeaderSize)); |
__ CopyBytes(string, result_pos, string_length, scratch); |
- __ add(Operand(index), Immediate(1)); |
+ __ add(index, Immediate(1)); |
__ bind(&loop_1_condition); |
__ cmp(index, array_length_operand); |
__ j(less, &loop_1); // End while (index < length). |
@@ -3490,7 +3561,7 @@ |
__ lea(string, |
FieldOperand(string, SeqAsciiString::kHeaderSize)); |
__ CopyBytes(string, result_pos, string_length, scratch); |
- __ add(Operand(index), Immediate(1)); |
+ __ add(index, Immediate(1)); |
__ cmp(index, array_length_operand); |
__ j(less, &loop_2); // End while (index < length). |
@@ -3531,7 +3602,7 @@ |
__ lea(string, |
FieldOperand(string, SeqAsciiString::kHeaderSize)); |
__ CopyBytes(string, result_pos, string_length, scratch); |
- __ add(Operand(index), Immediate(1)); |
+ __ add(index, Immediate(1)); |
__ cmp(index, array_length_operand); |
__ j(less, &loop_3); // End while (index < length). |
@@ -3543,7 +3614,7 @@ |
__ bind(&done); |
__ mov(eax, result_operand); |
// Drop temp values from the stack, and restore context register. |
- __ add(Operand(esp), Immediate(3 * kPointerSize)); |
+ __ add(esp, Immediate(3 * kPointerSize)); |
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
decrement_stack_height(); |
@@ -3823,9 +3894,9 @@ |
if (ShouldInlineSmiCase(expr->op())) { |
if (expr->op() == Token::INC) { |
- __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
+ __ add(eax, Immediate(Smi::FromInt(1))); |
} else { |
- __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
+ __ sub(eax, Immediate(Smi::FromInt(1))); |
} |
__ j(overflow, &stub_call, Label::kNear); |
// We could eliminate this smi check if we split the code at |
@@ -3835,9 +3906,9 @@ |
__ bind(&stub_call); |
// Call stub. Undo operation first. |
if (expr->op() == Token::INC) { |
- __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
+ __ sub(eax, Immediate(Smi::FromInt(1))); |
} else { |
- __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
+ __ add(eax, Immediate(Smi::FromInt(1))); |
} |
} |
@@ -3956,10 +4027,14 @@ |
void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
- Handle<String> check, |
- Label* if_true, |
- Label* if_false, |
- Label* fall_through) { |
+ Handle<String> check) { |
+ Label materialize_true, materialize_false; |
+ Label* if_true = NULL; |
+ Label* if_false = NULL; |
+ Label* fall_through = NULL; |
+ context()->PrepareTest(&materialize_true, &materialize_false, |
+ &if_true, &if_false, &fall_through); |
+ |
{ AccumulatorValueContext context(this); |
VisitForTypeofValue(expr); |
} |
@@ -3998,8 +4073,11 @@ |
Split(not_zero, if_true, if_false, fall_through); |
} else if (check->Equals(isolate()->heap()->function_symbol())) { |
__ JumpIfSmi(eax, if_false); |
- __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx); |
- Split(above_equal, if_true, if_false, fall_through); |
+ STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
+ __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx); |
+ __ j(equal, if_true); |
+ __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE); |
+ Split(equal, if_true, if_false, fall_through); |
} else if (check->Equals(isolate()->heap()->object_symbol())) { |
__ JumpIfSmi(eax, if_false); |
if (!FLAG_harmony_typeof) { |
@@ -4017,28 +4095,20 @@ |
} else { |
if (if_false != fall_through) __ jmp(if_false); |
} |
+ context()->Plug(if_true, if_false); |
} |
-void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr, |
- Label* if_true, |
- Label* if_false, |
- Label* fall_through) { |
- VisitForAccumulatorValue(expr); |
- PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
- |
- __ cmp(eax, isolate()->factory()->undefined_value()); |
- Split(equal, if_true, if_false, fall_through); |
-} |
- |
- |
void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
Comment cmnt(masm_, "[ CompareOperation"); |
SetSourcePosition(expr->position()); |
+ // First we try a fast inlined version of the compare when one of |
+ // the operands is a literal. |
+ if (TryLiteralCompare(expr)) return; |
+ |
// Always perform the comparison for its control flow. Pack the result |
// into the expression's context after the comparison is performed. |
- |
Label materialize_true, materialize_false; |
Label* if_true = NULL; |
Label* if_false = NULL; |
@@ -4046,16 +4116,9 @@ |
context()->PrepareTest(&materialize_true, &materialize_false, |
&if_true, &if_false, &fall_through); |
- // First we try a fast inlined version of the compare when one of |
- // the operands is a literal. |
- if (TryLiteralCompare(expr, if_true, if_false, fall_through)) { |
- context()->Plug(if_true, if_false); |
- return; |
- } |
- |
Token::Value op = expr->op(); |
VisitForStackValue(expr->left()); |
- switch (expr->op()) { |
+ switch (op) { |
case Token::IN: |
VisitForStackValue(expr->right()); |
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
@@ -4071,7 +4134,7 @@ |
__ CallStub(&stub); |
decrement_stack_height(2); |
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
- __ test(eax, Operand(eax)); |
+ __ test(eax, eax); |
// The stub returns 0 for true. |
Split(zero, if_true, if_false, fall_through); |
break; |
@@ -4080,11 +4143,8 @@ |
default: { |
VisitForAccumulatorValue(expr->right()); |
Condition cc = no_condition; |
- bool strict = false; |
switch (op) { |
case Token::EQ_STRICT: |
- strict = true; |
- // Fall through |
case Token::EQ: |
cc = equal; |
__ pop(edx); |
@@ -4120,10 +4180,10 @@ |
JumpPatchSite patch_site(masm_); |
if (inline_smi_code) { |
Label slow_case; |
- __ mov(ecx, Operand(edx)); |
- __ or_(ecx, Operand(eax)); |
+ __ mov(ecx, edx); |
+ __ or_(ecx, eax); |
patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
- __ cmp(edx, Operand(eax)); |
+ __ cmp(edx, eax); |
Split(cc, if_true, if_false, NULL); |
__ bind(&slow_case); |
} |
@@ -4135,7 +4195,7 @@ |
patch_site.EmitPatchInfo(); |
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
- __ test(eax, Operand(eax)); |
+ __ test(eax, eax); |
Split(cc, if_true, if_false, fall_through); |
} |
} |
@@ -4146,7 +4206,9 @@ |
} |
-void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { |
+void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, |
+ Expression* sub_expr, |
+ NilValue nil) { |
Label materialize_true, materialize_false; |
Label* if_true = NULL; |
Label* if_false = NULL; |
@@ -4154,15 +4216,20 @@ |
context()->PrepareTest(&materialize_true, &materialize_false, |
&if_true, &if_false, &fall_through); |
- VisitForAccumulatorValue(expr->expression()); |
+ VisitForAccumulatorValue(sub_expr); |
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
- |
- __ cmp(eax, isolate()->factory()->null_value()); |
- if (expr->is_strict()) { |
+ Handle<Object> nil_value = nil == kNullValue ? |
+ isolate()->factory()->null_value() : |
+ isolate()->factory()->undefined_value(); |
+ __ cmp(eax, nil_value); |
+ if (expr->op() == Token::EQ_STRICT) { |
Split(equal, if_true, if_false, fall_through); |
} else { |
+ Handle<Object> other_nil_value = nil == kNullValue ? |
+ isolate()->factory()->undefined_value() : |
+ isolate()->factory()->null_value(); |
__ j(equal, if_true); |
- __ cmp(eax, isolate()->factory()->undefined_value()); |
+ __ cmp(eax, other_nil_value); |
__ j(equal, if_true); |
__ JumpIfSmi(eax, if_false); |
// It can be an undetectable object. |
@@ -4229,7 +4296,7 @@ |
// Cook return address on top of stack (smi encoded Code* delta) |
ASSERT(!result_register().is(edx)); |
__ pop(edx); |
- __ sub(Operand(edx), Immediate(masm_->CodeObject())); |
+ __ sub(edx, Immediate(masm_->CodeObject())); |
STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
STATIC_ASSERT(kSmiTag == 0); |
__ SmiTag(edx); |
@@ -4245,8 +4312,8 @@ |
// Uncook return address. |
__ pop(edx); |
__ SmiUntag(edx); |
- __ add(Operand(edx), Immediate(masm_->CodeObject())); |
- __ jmp(Operand(edx)); |
+ __ add(edx, Immediate(masm_->CodeObject())); |
+ __ jmp(edx); |
} |