summaryrefslogtreecommitdiff
path: root/deps/v8/src/ia32/full-codegen-ia32.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ia32/full-codegen-ia32.cc')
-rw-r--r--deps/v8/src/ia32/full-codegen-ia32.cc358
1 files changed, 144 insertions, 214 deletions
diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc
index 33d5cabad..ca6ce6e31 100644
--- a/deps/v8/src/ia32/full-codegen-ia32.cc
+++ b/deps/v8/src/ia32/full-codegen-ia32.cc
@@ -138,7 +138,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// function calls.
if (info->is_strict_mode() || info->is_native()) {
Label ok;
- __ test(ecx, ecx);
+ __ test(ecx, Operand(ecx));
__ j(zero, &ok, Label::kNear);
// +1 for return address.
int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
@@ -147,11 +147,6 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ 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.
@@ -205,12 +200,11 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Store it in the context.
int context_offset = Context::SlotOffset(var->index());
__ mov(Operand(esi, context_offset), eax);
- // Update the write barrier. This clobbers eax and ebx.
- __ RecordWriteContextSlot(esi,
- context_offset,
- eax,
- ebx,
- kDontSaveFPRegs);
+ // 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);
}
}
}
@@ -266,7 +260,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
int ignored = 0;
- EmitDeclaration(scope()->function(), CONST, NULL, &ignored);
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
@@ -371,10 +365,10 @@ void FullCodeGenerator::EmitReturnSequence() {
void FullCodeGenerator::verify_stack_height() {
ASSERT(FLAG_verify_stack_height);
- __ sub(ebp, Immediate(kPointerSize * stack_height()));
- __ cmp(ebp, esp);
+ __ sub(Operand(ebp), Immediate(kPointerSize * stack_height()));
+ __ cmp(ebp, Operand(esp));
__ Assert(equal, "Full codegen stack height not as expected.");
- __ add(ebp, Immediate(kPointerSize * stack_height()));
+ __ add(Operand(ebp), Immediate(kPointerSize * stack_height()));
}
@@ -603,7 +597,7 @@ void FullCodeGenerator::DoTest(Expression* condition,
ToBooleanStub stub(result_register());
__ push(result_register());
__ CallStub(&stub, condition->test_id());
- __ test(result_register(), result_register());
+ __ test(result_register(), Operand(result_register()));
// The stub returns nonzero for true.
Split(not_zero, if_true, if_false, fall_through);
}
@@ -667,12 +661,11 @@ void FullCodeGenerator::SetVar(Variable* var,
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));
- __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
+ __ RecordWrite(scratch0, offset, src, scratch1);
}
}
@@ -704,7 +697,7 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
- VariableMode mode,
+ Variable::Mode mode,
FunctionLiteral* function,
int* global_count) {
// If it was not possible to allocate the variable at compile time, we
@@ -722,7 +715,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
__ mov(StackOperand(variable), result_register());
- } else if (mode == CONST || mode == LET) {
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
Comment cmnt(masm_, "[ Declaration");
__ mov(StackOperand(variable),
Immediate(isolate()->factory()->the_hole_value()));
@@ -745,16 +738,11 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
__ mov(ContextOperand(esi, variable->index()), result_register());
- // 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);
+ int offset = Context::SlotOffset(variable->index());
+ __ mov(ebx, esi);
+ __ RecordWrite(ebx, offset, result_register(), ecx);
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
- } else if (mode == CONST || mode == LET) {
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
Comment cmnt(masm_, "[ Declaration");
__ mov(ContextOperand(esi, variable->index()),
Immediate(isolate()->factory()->the_hole_value()));
@@ -768,8 +756,10 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
__ push(esi);
__ push(Immediate(variable->name()));
// Declaration nodes are always introduced in one of three modes.
- ASSERT(mode == VAR || mode == CONST || mode == LET);
- PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE;
+ ASSERT(mode == Variable::VAR ||
+ mode == Variable::CONST ||
+ mode == Variable::LET);
+ PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ push(Immediate(Smi::FromInt(attr)));
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
@@ -778,7 +768,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
increment_stack_height(3);
if (function != NULL) {
VisitForStackValue(function);
- } else if (mode == CONST || mode == LET) {
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
__ push(Immediate(isolate()->factory()->the_hole_value()));
increment_stack_height();
} else {
@@ -845,10 +835,10 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
if (inline_smi_code) {
Label slow_case;
__ mov(ecx, edx);
- __ or_(ecx, eax);
+ __ or_(ecx, Operand(eax));
patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
- __ cmp(edx, eax);
+ __ cmp(edx, Operand(eax));
__ j(not_equal, &next_test);
__ Drop(1); // Switch value is no longer needed.
__ jmp(clause->body_target());
@@ -860,7 +850,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
__ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
patch_site.EmitPatchInfo();
- __ test(eax, eax);
+ __ test(eax, Operand(eax));
__ j(not_equal, &next_test);
__ Drop(1); // Switch value is no longer needed.
__ jmp(clause->body_target());
@@ -949,7 +939,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// For all objects but the receiver, check that the cache is empty.
Label check_prototype;
- __ cmp(ecx, eax);
+ __ cmp(ecx, Operand(eax));
__ j(equal, &check_prototype, Label::kNear);
__ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
__ cmp(edx, isolate()->factory()->empty_fixed_array());
@@ -1031,9 +1021,9 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ push(ecx); // Enumerable.
__ push(ebx); // Current entry.
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
- __ test(eax, eax);
+ __ test(eax, Operand(eax));
__ j(equal, loop_statement.continue_label());
- __ mov(ebx, eax);
+ __ mov(ebx, Operand(eax));
// Update the 'each' property or variable from the possibly filtered
// entry in register ebx.
@@ -1057,7 +1047,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Remove the pointers stored on the stack.
__ bind(loop_statement.break_label());
- __ add(esp, Immediate(5 * kPointerSize));
+ __ add(Operand(esp), Immediate(5 * kPointerSize));
decrement_stack_height(ForIn::kElementCount);
// Exit and decrement the loop depth.
@@ -1199,22 +1189,16 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (var->mode() == DYNAMIC_GLOBAL) {
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done);
- } else if (var->mode() == DYNAMIC_LOCAL) {
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
Variable* local = var->local_if_not_shadowed();
__ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
- if (local->mode() == CONST ||
- local->mode() == LET) {
+ if (local->mode() == Variable::CONST) {
__ cmp(eax, isolate()->factory()->the_hole_value());
__ j(not_equal, done);
- if (local->mode() == CONST) {
- __ mov(eax, isolate()->factory()->undefined_value());
- } else { // LET
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- }
+ __ mov(eax, isolate()->factory()->undefined_value());
}
__ jmp(done);
}
@@ -1247,7 +1231,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
Comment cmnt(masm_, var->IsContextSlot()
? "Context variable"
: "Stack variable");
- if (var->mode() != LET && var->mode() != CONST) {
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
context()->Plug(var);
} else {
// Let and const need a read barrier.
@@ -1255,10 +1239,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
GetVar(eax, var);
__ cmp(eax, isolate()->factory()->the_hole_value());
__ j(not_equal, &done, Label::kNear);
- if (var->mode() == LET) {
+ if (var->mode() == Variable::LET) {
__ push(Immediate(var->name()));
__ CallRuntime(Runtime::kThrowReferenceError, 1);
- } else { // CONST
+ } else { // Variable::CONST
__ mov(eax, isolate()->factory()->undefined_value());
}
__ bind(&done);
@@ -1496,18 +1480,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
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.
- __ RecordWriteField(ebx, offset, result_register(), ecx,
- kDontSaveFPRegs,
- EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- __ 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);
+ __ RecordWrite(ebx, offset, result_register(), ecx);
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
}
@@ -1667,7 +1641,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
__ pop(edx);
decrement_stack_height();
__ mov(ecx, eax);
- __ or_(eax, edx);
+ __ or_(eax, Operand(edx));
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
@@ -1717,32 +1691,32 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
break;
}
case Token::ADD:
- __ add(eax, ecx);
+ __ add(eax, Operand(ecx));
__ j(overflow, &stub_call);
break;
case Token::SUB:
- __ sub(eax, ecx);
+ __ sub(eax, Operand(ecx));
__ j(overflow, &stub_call);
break;
case Token::MUL: {
__ SmiUntag(eax);
- __ imul(eax, ecx);
+ __ imul(eax, Operand(ecx));
__ j(overflow, &stub_call);
- __ test(eax, eax);
+ __ test(eax, Operand(eax));
__ j(not_zero, &done, Label::kNear);
__ mov(ebx, edx);
- __ or_(ebx, ecx);
+ __ or_(ebx, Operand(ecx));
__ j(negative, &stub_call);
break;
}
case Token::BIT_OR:
- __ or_(eax, ecx);
+ __ or_(eax, Operand(ecx));
break;
case Token::BIT_AND:
- __ and_(eax, ecx);
+ __ and_(eax, Operand(ecx));
break;
case Token::BIT_XOR:
- __ xor_(eax, ecx);
+ __ xor_(eax, Operand(ecx));
break;
default:
UNREACHABLE();
@@ -1864,7 +1838,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- } else if (var->mode() == LET && op != Token::INIT_LET) {
+ } else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
if (var->IsLookupSlot()) {
__ push(eax); // Value.
@@ -1885,12 +1859,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ mov(location, eax);
if (var->IsContextSlot()) {
__ mov(edx, eax);
- int offset = Context::SlotOffset(var->index());
- __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
+ __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
}
}
- } else if (var->mode() != CONST) {
+ } else if (var->mode() != Variable::CONST) {
// Assignment to var or initializing assignment to let.
if (var->IsStackAllocated() || var->IsContextSlot()) {
MemOperand location = VarOperand(var, ecx);
@@ -1904,8 +1877,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ mov(location, eax);
if (var->IsContextSlot()) {
__ mov(edx, eax);
- int offset = Context::SlotOffset(var->index());
- __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
+ __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
}
} else {
ASSERT(var->IsLookupSlot());
@@ -2097,29 +2069,8 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
}
// 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));
@@ -2143,8 +2094,10 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
// Push the strict mode flag. In harmony mode every eval call
// is a strict mode eval call.
- StrictModeFlag strict_mode =
- FLAG_harmony_scoping ? kStrictMode : strict_mode_flag();
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
__ push(Immediate(Smi::FromInt(strict_mode)));
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
@@ -2187,7 +2140,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// context lookup in the runtime system.
Label done;
Variable* var = proxy->var();
- if (!var->IsUnallocated() && var->mode() == DYNAMIC_GLOBAL) {
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
@@ -2485,9 +2438,9 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
STATIC_ASSERT(kPointerSize == 4);
__ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
// Calculate location of the first key name.
- __ add(ebx,
- Immediate(FixedArray::kHeaderSize +
- DescriptorArray::kFirstIndex * kPointerSize));
+ __ add(Operand(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;
@@ -2496,9 +2449,9 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
__ mov(edx, FieldOperand(ebx, 0));
__ cmp(edx, FACTORY->value_of_symbol());
__ j(equal, if_false);
- __ add(ebx, Immediate(kPointerSize));
+ __ add(Operand(ebx), Immediate(kPointerSize));
__ bind(&entry);
- __ cmp(ebx, ecx);
+ __ cmp(ebx, Operand(ecx));
__ j(not_equal, &loop);
// Reload map as register ebx was used as temporary above.
@@ -2638,7 +2591,7 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
__ pop(ebx);
decrement_stack_height();
- __ cmp(eax, ebx);
+ __ cmp(eax, Operand(ebx));
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Split(equal, if_true, if_false, fall_through);
@@ -2694,24 +2647,20 @@ void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
// 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);
-
- __ 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 JS 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);
+
+ // Check if the constructor in the map is a function.
__ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
__ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
__ j(not_equal, &non_function_constructor);
@@ -2792,8 +2741,8 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope fscope(SSE2);
__ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
- __ movd(xmm1, ebx);
- __ movd(xmm0, eax);
+ __ movd(xmm1, Operand(ebx));
+ __ movd(xmm0, Operand(eax));
__ cvtss2sd(xmm1, xmm1);
__ xorps(xmm0, xmm1);
__ subsd(xmm0, xmm1);
@@ -2894,11 +2843,10 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
// 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);
- __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
+ __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
__ bind(&done);
context()->Plug(eax);
@@ -3171,14 +3119,14 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
__ mov(index_1, Operand(esp, 1 * kPointerSize));
__ mov(index_2, Operand(esp, 0));
__ mov(temp, index_1);
- __ or_(temp, index_2);
+ __ or_(temp, Operand(index_2));
__ JumpIfNotSmi(temp, &slow_case);
// Check that both indices are valid.
__ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
- __ cmp(temp, index_1);
+ __ cmp(temp, Operand(index_1));
__ j(below_equal, &slow_case);
- __ cmp(temp, index_2);
+ __ cmp(temp, Operand(index_2));
__ j(below_equal, &slow_case);
// Bring addresses into index1 and index2.
@@ -3191,35 +3139,16 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
__ mov(Operand(index_2, 0), object);
__ mov(Operand(index_1, 0), temp);
- 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.)
-
- // 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(&no_remembered_set);
+ Label new_space;
+ __ InNewSpace(elements, temp, equal, &new_space);
+ __ mov(object, elements);
+ __ RecordWriteHelper(object, index_1, temp);
+ __ RecordWriteHelper(elements, index_2, temp);
+
+ __ bind(&new_space);
// We are done. Drop elements from the stack, and return undefined.
- __ add(esp, Immediate(3 * kPointerSize));
+ __ add(Operand(esp), Immediate(3 * kPointerSize));
__ mov(eax, isolate()->factory()->undefined_value());
__ jmp(&done);
@@ -3292,11 +3221,11 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
__ pop(left);
Label done, fail, ok;
- __ cmp(left, right);
+ __ cmp(left, Operand(right));
__ j(equal, &ok);
// Fail if either is a non-HeapObject.
__ mov(tmp, left);
- __ and_(tmp, right);
+ __ and_(Operand(tmp), right);
__ JumpIfSmi(tmp, &fail);
__ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
__ CmpInstanceType(tmp, JS_REGEXP_TYPE);
@@ -3387,7 +3316,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
Operand separator_operand = Operand(esp, 2 * kPointerSize);
Operand result_operand = Operand(esp, 1 * kPointerSize);
Operand array_length_operand = Operand(esp, 0);
- __ sub(esp, Immediate(2 * kPointerSize));
+ __ sub(Operand(esp), Immediate(2 * kPointerSize));
__ cld();
// Check that the array is a JSArray
__ JumpIfSmi(array, &bailout);
@@ -3423,7 +3352,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
// Live loop registers: index, array_length, string,
// scratch, string_length, elements.
if (FLAG_debug_code) {
- __ cmp(index, array_length);
+ __ cmp(index, Operand(array_length));
__ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
}
__ bind(&loop);
@@ -3441,8 +3370,8 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ add(string_length,
FieldOperand(string, SeqAsciiString::kLengthOffset));
__ j(overflow, &bailout);
- __ add(index, Immediate(1));
- __ cmp(index, array_length);
+ __ add(Operand(index), Immediate(1));
+ __ cmp(index, Operand(array_length));
__ j(less, &loop);
// If array_length is 1, return elements[0], a string.
@@ -3476,10 +3405,10 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
// to string_length.
__ mov(scratch, separator_operand);
__ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
- __ sub(string_length, scratch); // May be negative, temporarily.
+ __ sub(string_length, Operand(scratch)); // May be negative, temporarily.
__ imul(scratch, array_length_operand);
__ j(overflow, &bailout);
- __ add(string_length, scratch);
+ __ add(string_length, Operand(scratch));
__ j(overflow, &bailout);
__ shr(string_length, 1);
@@ -3520,7 +3449,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ lea(string,
FieldOperand(string, SeqAsciiString::kHeaderSize));
__ CopyBytes(string, result_pos, string_length, scratch);
- __ add(index, Immediate(1));
+ __ add(Operand(index), Immediate(1));
__ bind(&loop_1_condition);
__ cmp(index, array_length_operand);
__ j(less, &loop_1); // End while (index < length).
@@ -3561,7 +3490,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ lea(string,
FieldOperand(string, SeqAsciiString::kHeaderSize));
__ CopyBytes(string, result_pos, string_length, scratch);
- __ add(index, Immediate(1));
+ __ add(Operand(index), Immediate(1));
__ cmp(index, array_length_operand);
__ j(less, &loop_2); // End while (index < length).
@@ -3602,7 +3531,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ lea(string,
FieldOperand(string, SeqAsciiString::kHeaderSize));
__ CopyBytes(string, result_pos, string_length, scratch);
- __ add(index, Immediate(1));
+ __ add(Operand(index), Immediate(1));
__ cmp(index, array_length_operand);
__ j(less, &loop_3); // End while (index < length).
@@ -3614,7 +3543,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ bind(&done);
__ mov(eax, result_operand);
// Drop temp values from the stack, and restore context register.
- __ add(esp, Immediate(3 * kPointerSize));
+ __ add(Operand(esp), Immediate(3 * kPointerSize));
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
decrement_stack_height();
@@ -3894,9 +3823,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
if (ShouldInlineSmiCase(expr->op())) {
if (expr->op() == Token::INC) {
- __ add(eax, Immediate(Smi::FromInt(1)));
+ __ add(Operand(eax), Immediate(Smi::FromInt(1)));
} else {
- __ sub(eax, Immediate(Smi::FromInt(1)));
+ __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
}
__ j(overflow, &stub_call, Label::kNear);
// We could eliminate this smi check if we split the code at
@@ -3906,9 +3835,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ bind(&stub_call);
// Call stub. Undo operation first.
if (expr->op() == Token::INC) {
- __ sub(eax, Immediate(Smi::FromInt(1)));
+ __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
} else {
- __ add(eax, Immediate(Smi::FromInt(1)));
+ __ add(Operand(eax), Immediate(Smi::FromInt(1)));
}
}
@@ -4027,14 +3956,10 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
- 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);
-
+ Handle<String> check,
+ Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
{ AccumulatorValueContext context(this);
VisitForTypeofValue(expr);
}
@@ -4073,11 +3998,8 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Split(not_zero, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->function_symbol())) {
__ JumpIfSmi(eax, if_false);
- 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);
+ __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx);
+ Split(above_equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(eax, if_false);
if (!FLAG_harmony_typeof) {
@@ -4095,7 +4017,18 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
} 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);
}
@@ -4103,12 +4036,9 @@ 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;
@@ -4116,9 +4046,16 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
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 (op) {
+ switch (expr->op()) {
case Token::IN:
VisitForStackValue(expr->right());
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
@@ -4134,7 +4071,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
__ CallStub(&stub);
decrement_stack_height(2);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- __ test(eax, eax);
+ __ test(eax, Operand(eax));
// The stub returns 0 for true.
Split(zero, if_true, if_false, fall_through);
break;
@@ -4180,10 +4117,10 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
JumpPatchSite patch_site(masm_);
if (inline_smi_code) {
Label slow_case;
- __ mov(ecx, edx);
- __ or_(ecx, eax);
+ __ mov(ecx, Operand(edx));
+ __ or_(ecx, Operand(eax));
patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
- __ cmp(edx, eax);
+ __ cmp(edx, Operand(eax));
Split(cc, if_true, if_false, NULL);
__ bind(&slow_case);
}
@@ -4195,7 +4132,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
patch_site.EmitPatchInfo();
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- __ test(eax, eax);
+ __ test(eax, Operand(eax));
Split(cc, if_true, if_false, fall_through);
}
}
@@ -4206,9 +4143,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
}
-void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
- Expression* sub_expr,
- NilValue nil) {
+void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
@@ -4216,20 +4151,15 @@ void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
context()->PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
- VisitForAccumulatorValue(sub_expr);
+ VisitForAccumulatorValue(expr->expression());
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- Handle<Object> nil_value = nil == kNullValue ?
- isolate()->factory()->null_value() :
- isolate()->factory()->undefined_value();
- __ cmp(eax, nil_value);
- if (expr->op() == Token::EQ_STRICT) {
+
+ __ cmp(eax, isolate()->factory()->null_value());
+ if (expr->is_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, other_nil_value);
+ __ cmp(eax, isolate()->factory()->undefined_value());
__ j(equal, if_true);
__ JumpIfSmi(eax, if_false);
// It can be an undetectable object.
@@ -4296,7 +4226,7 @@ void FullCodeGenerator::EnterFinallyBlock() {
// Cook return address on top of stack (smi encoded Code* delta)
ASSERT(!result_register().is(edx));
__ pop(edx);
- __ sub(edx, Immediate(masm_->CodeObject()));
+ __ sub(Operand(edx), Immediate(masm_->CodeObject()));
STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
STATIC_ASSERT(kSmiTag == 0);
__ SmiTag(edx);
@@ -4312,8 +4242,8 @@ void FullCodeGenerator::ExitFinallyBlock() {
// Uncook return address.
__ pop(edx);
__ SmiUntag(edx);
- __ add(edx, Immediate(masm_->CodeObject()));
- __ jmp(edx);
+ __ add(Operand(edx), Immediate(masm_->CodeObject()));
+ __ jmp(Operand(edx));
}