Upgrade to V8 3.3
Merge V8 at 3.3.10.39
Simple merge required updates to makefiles only.
Bug: 5688872
Change-Id: I14703f418235f5ce6013b9b3e2e502407a9f6dfd
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 13394cb..6e66b6e 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -73,7 +73,69 @@
shr(addr, Page::kRegionSizeLog2);
// Set dirty mark for region.
- bts(Operand(object, Page::kDirtyFlagOffset), addr);
+ // Bit tests with a memory operand should be avoided on Intel processors,
+ // as they usually have long latency and multiple uops. We load the bit base
+ // operand to a register at first and store it back after bit set.
+ mov(scratch, Operand(object, Page::kDirtyFlagOffset));
+ bts(Operand(scratch), addr);
+ mov(Operand(object, Page::kDirtyFlagOffset), scratch);
+}
+
+
+void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
+ XMMRegister scratch_reg,
+ Register result_reg) {
+ Label done;
+ ExternalReference zero_ref = ExternalReference::address_of_zero();
+ movdbl(scratch_reg, Operand::StaticVariable(zero_ref));
+ Set(result_reg, Immediate(0));
+ ucomisd(input_reg, scratch_reg);
+ j(below, &done, Label::kNear);
+ ExternalReference half_ref = ExternalReference::address_of_one_half();
+ movdbl(scratch_reg, Operand::StaticVariable(half_ref));
+ addsd(scratch_reg, input_reg);
+ cvttsd2si(result_reg, Operand(scratch_reg));
+ test(result_reg, Immediate(0xFFFFFF00));
+ j(zero, &done, Label::kNear);
+ Set(result_reg, Immediate(255));
+ bind(&done);
+}
+
+
+void MacroAssembler::ClampUint8(Register reg) {
+ Label done;
+ test(reg, Immediate(0xFFFFFF00));
+ j(zero, &done, Label::kNear);
+ setcc(negative, reg); // 1 if negative, 0 if positive.
+ dec_b(reg); // 0 if negative, 255 if positive.
+ bind(&done);
+}
+
+
+void MacroAssembler::InNewSpace(Register object,
+ Register scratch,
+ Condition cc,
+ Label* branch,
+ Label::Distance branch_near) {
+ ASSERT(cc == equal || cc == not_equal);
+ if (Serializer::enabled()) {
+ // Can't do arithmetic on external references if it might get serialized.
+ mov(scratch, Operand(object));
+ // The mask isn't really an address. We load it as an external reference in
+ // case the size of the new space is different between the snapshot maker
+ // and the running system.
+ and_(Operand(scratch),
+ Immediate(ExternalReference::new_space_mask(isolate())));
+ cmp(Operand(scratch),
+ Immediate(ExternalReference::new_space_start(isolate())));
+ j(cc, branch, branch_near);
+ } else {
+ int32_t new_space_start = reinterpret_cast<int32_t>(
+ ExternalReference::new_space_start(isolate()).address());
+ lea(scratch, Operand(object, -new_space_start));
+ and_(scratch, isolate()->heap()->NewSpaceMask());
+ j(cc, branch, branch_near);
+ }
}
@@ -83,14 +145,14 @@
Register scratch) {
// First, check if a write barrier is even needed. The tests below
// catch stores of Smis and stores into young gen.
- NearLabel done;
+ Label done;
// Skip barrier if writing a smi.
ASSERT_EQ(0, kSmiTag);
test(value, Immediate(kSmiTagMask));
- j(zero, &done);
+ j(zero, &done, Label::kNear);
- InNewSpace(object, value, equal, &done);
+ InNewSpace(object, value, equal, &done, Label::kNear);
// The offset is relative to a tagged or untagged HeapObject pointer,
// so either offset or offset + kHeapObjectTag must be a
@@ -220,16 +282,30 @@
void MacroAssembler::CheckMap(Register obj,
Handle<Map> map,
Label* fail,
- bool is_heap_object) {
- if (!is_heap_object) {
- test(obj, Immediate(kSmiTagMask));
- j(zero, fail);
+ SmiCheckType smi_check_type) {
+ if (smi_check_type == DO_SMI_CHECK) {
+ JumpIfSmi(obj, fail);
}
cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
j(not_equal, fail);
}
+void MacroAssembler::DispatchMap(Register obj,
+ Handle<Map> map,
+ Handle<Code> success,
+ SmiCheckType smi_check_type) {
+ Label fail;
+ if (smi_check_type == DO_SMI_CHECK) {
+ JumpIfSmi(obj, &fail);
+ }
+ cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
+ j(equal, success);
+
+ bind(&fail);
+}
+
+
Condition MacroAssembler::IsObjectStringType(Register heap_object,
Register map,
Register instance_type) {
@@ -511,9 +587,9 @@
// not NULL. The frame pointer is NULL in the exception handler of
// a JS entry frame.
Set(esi, Immediate(0)); // Tentatively set context pointer to NULL.
- NearLabel skip;
+ Label skip;
cmp(ebp, 0);
- j(equal, &skip, not_taken);
+ j(equal, &skip, Label::kNear);
mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
bind(&skip);
@@ -538,12 +614,12 @@
mov(esp, Operand::StaticVariable(handler_address));
// Unwind the handlers until the ENTRY handler is found.
- NearLabel loop, done;
+ Label loop, done;
bind(&loop);
// Load the type of the current stack handler.
const int kStateOffset = StackHandlerConstants::kStateOffset;
cmp(Operand(esp, kStateOffset), Immediate(StackHandler::ENTRY));
- j(equal, &done);
+ j(equal, &done, Label::kNear);
// Fetch the next handler in the list.
const int kNextOffset = StackHandlerConstants::kNextOffset;
mov(esp, Operand(esp, kNextOffset));
@@ -614,7 +690,7 @@
// Check if both contexts are the same.
cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
- j(equal, &same_contexts, taken);
+ j(equal, &same_contexts);
// Compare security tokens, save holder_reg on the stack so we can use it
// as a temporary register.
@@ -644,7 +720,7 @@
mov(scratch, FieldOperand(scratch, token_offset));
cmp(scratch, FieldOperand(holder_reg, token_offset));
pop(holder_reg);
- j(not_equal, miss, not_taken);
+ j(not_equal, miss);
bind(&same_contexts);
}
@@ -732,9 +808,9 @@
mov(top_reg, result);
}
add(Operand(top_reg), Immediate(object_size));
- j(carry, gc_required, not_taken);
+ j(carry, gc_required);
cmp(top_reg, Operand::StaticVariable(new_space_allocation_limit));
- j(above, gc_required, not_taken);
+ j(above, gc_required);
// Update allocation top.
UpdateAllocationTopHelper(top_reg, scratch);
@@ -831,9 +907,9 @@
mov(result_end, object_size);
}
add(result_end, Operand(result));
- j(carry, gc_required, not_taken);
+ j(carry, gc_required);
cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
- j(above, gc_required, not_taken);
+ j(above, gc_required);
// Tag result if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -1062,9 +1138,9 @@
Label* then_label) {
Label ok;
test(result, Operand(result));
- j(not_zero, &ok, taken);
+ j(not_zero, &ok);
test(op, Operand(op));
- j(sign, then_label, not_taken);
+ j(sign, then_label);
bind(&ok);
}
@@ -1076,10 +1152,10 @@
Label* then_label) {
Label ok;
test(result, Operand(result));
- j(not_zero, &ok, taken);
+ j(not_zero, &ok);
mov(scratch, Operand(op1));
or_(scratch, Operand(op2));
- j(sign, then_label, not_taken);
+ j(sign, then_label);
bind(&ok);
}
@@ -1090,17 +1166,17 @@
Label* miss) {
// Check that the receiver isn't a smi.
test(function, Immediate(kSmiTagMask));
- j(zero, miss, not_taken);
+ j(zero, miss);
// Check that the function really is a function.
CmpObjectType(function, JS_FUNCTION_TYPE, result);
- j(not_equal, miss, not_taken);
+ j(not_equal, miss);
// Make sure that the function has an instance prototype.
Label non_instance;
movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
- j(not_zero, &non_instance, not_taken);
+ j(not_zero, &non_instance);
// Get the prototype or initial map from the function.
mov(result,
@@ -1110,7 +1186,7 @@
// simply miss the cache instead. This will allow us to allocate a
// prototype object on-demand in the runtime system.
cmp(Operand(result), Immediate(isolate()->factory()->the_hole_value()));
- j(equal, miss, not_taken);
+ j(equal, miss);
// If the function does not have an initial map, we're done.
Label done;
@@ -1131,9 +1207,9 @@
}
-void MacroAssembler::CallStub(CodeStub* stub) {
+void MacroAssembler::CallStub(CodeStub* stub, unsigned ast_id) {
ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
- call(stub->GetCode(), RelocInfo::CODE_TARGET);
+ call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id);
}
@@ -1391,7 +1467,7 @@
// Check if the result handle holds 0.
test(eax, Operand(eax));
- j(zero, &empty_handle, not_taken);
+ j(zero, &empty_handle);
// It was non-zero. Dereference to get the result value.
mov(eax, Operand(eax, 0));
bind(&prologue);
@@ -1401,7 +1477,7 @@
sub(Operand::StaticVariable(level_address), Immediate(1));
Assert(above_equal, "Invalid HandleScope level");
cmp(edi, Operand::StaticVariable(limit_address));
- j(not_equal, &delete_allocated_handles, not_taken);
+ j(not_equal, &delete_allocated_handles);
bind(&leave_exit_frame);
// Check if the function scheduled an exception.
@@ -1409,7 +1485,7 @@
ExternalReference::scheduled_exception_address(isolate());
cmp(Operand::StaticVariable(scheduled_exception_address),
Immediate(isolate()->factory()->the_hole_value()));
- j(not_equal, &promote_scheduled_exception, not_taken);
+ j(not_equal, &promote_scheduled_exception);
LeaveApiExitFrame();
ret(stack_space * kPointerSize);
bind(&promote_scheduled_exception);
@@ -1456,13 +1532,32 @@
}
+void MacroAssembler::SetCallKind(Register dst, CallKind call_kind) {
+ // This macro takes the dst register to make the code more readable
+ // at the call sites. However, the dst register has to be ecx to
+ // follow the calling convention which requires the call type to be
+ // in ecx.
+ ASSERT(dst.is(ecx));
+ if (call_kind == CALL_AS_FUNCTION) {
+ // Set to some non-zero smi by updating the least significant
+ // byte.
+ mov_b(Operand(dst), 1 << kSmiTagSize);
+ } else {
+ // Set to smi zero by clearing the register.
+ xor_(dst, Operand(dst));
+ }
+}
+
+
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
Handle<Code> code_constant,
const Operand& code_operand,
- NearLabel* done,
+ Label* done,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ Label::Distance done_near,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
bool definitely_matches = false;
Label invoke;
if (expected.is_immediate()) {
@@ -1512,10 +1607,13 @@
}
if (flag == CALL_FUNCTION) {
+ call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
+ SetCallKind(ecx, call_kind);
call(adaptor, RelocInfo::CODE_TARGET);
- if (post_call_generator != NULL) post_call_generator->Generate();
- jmp(done);
+ call_wrapper.AfterCall();
+ jmp(done, done_near);
} else {
+ SetCallKind(ecx, call_kind);
jmp(adaptor, RelocInfo::CODE_TARGET);
}
bind(&invoke);
@@ -1527,15 +1625,20 @@
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
- NearLabel done;
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
+ Label done;
InvokePrologue(expected, actual, Handle<Code>::null(), code,
- &done, flag, post_call_generator);
+ &done, flag, Label::kNear, call_wrapper,
+ call_kind);
if (flag == CALL_FUNCTION) {
+ call_wrapper.BeforeCall(CallSize(code));
+ SetCallKind(ecx, call_kind);
call(code);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ call_wrapper.AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
+ SetCallKind(ecx, call_kind);
jmp(code);
}
bind(&done);
@@ -1547,16 +1650,20 @@
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
- NearLabel done;
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
+ Label done;
Operand dummy(eax);
- InvokePrologue(expected, actual, code, dummy, &done,
- flag, post_call_generator);
+ InvokePrologue(expected, actual, code, dummy, &done, flag, Label::kNear,
+ call_wrapper, call_kind);
if (flag == CALL_FUNCTION) {
+ call_wrapper.BeforeCall(CallSize(code, rmode));
+ SetCallKind(ecx, call_kind);
call(code, rmode);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ call_wrapper.AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
+ SetCallKind(ecx, call_kind);
jmp(code, rmode);
}
bind(&done);
@@ -1566,7 +1673,8 @@
void MacroAssembler::InvokeFunction(Register fun,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
ASSERT(fun.is(edi));
mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
@@ -1575,14 +1683,15 @@
ParameterCount expected(ebx);
InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
- expected, actual, flag, post_call_generator);
+ expected, actual, flag, call_wrapper, call_kind);
}
void MacroAssembler::InvokeFunction(JSFunction* function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
ASSERT(function->is_compiled());
// Get the function and setup the context.
mov(edi, Immediate(Handle<JSFunction>(function)));
@@ -1594,18 +1703,18 @@
// code field in the function to allow recompilation to take effect
// without changing any of the call sites.
InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
- expected, actual, flag, post_call_generator);
+ expected, actual, flag, call_wrapper, call_kind);
} else {
Handle<Code> code(function->code());
InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET,
- flag, post_call_generator);
+ flag, call_wrapper, call_kind);
}
}
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ const CallWrapper& call_wrapper) {
// Calls are not allowed in some stubs.
ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
@@ -1615,7 +1724,7 @@
ParameterCount expected(0);
GetBuiltinFunction(edi, id);
InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
- expected, expected, flag, post_call_generator);
+ expected, expected, flag, call_wrapper, CALL_AS_METHOD);
}
void MacroAssembler::GetBuiltinFunction(Register target,
@@ -1681,7 +1790,7 @@
mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
if (emit_debug_code()) {
Label ok, fail;
- CheckMap(map, isolate()->factory()->meta_map(), &fail, false);
+ CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK);
jmp(&ok);
bind(&fail);
Abort("Global functions must have initial map");
@@ -1845,7 +1954,7 @@
void MacroAssembler::Check(Condition cc, const char* msg) {
Label L;
- j(cc, &L, taken);
+ j(cc, &L);
Abort(msg);
// will not return here
bind(&L);
@@ -1894,56 +2003,14 @@
}
-void MacroAssembler::JumpIfNotNumber(Register reg,
- TypeInfo info,
- Label* on_not_number) {
- if (emit_debug_code()) AbortIfSmi(reg);
- if (!info.IsNumber()) {
- cmp(FieldOperand(reg, HeapObject::kMapOffset),
- isolate()->factory()->heap_number_map());
- j(not_equal, on_not_number);
- }
-}
-
-
-void MacroAssembler::ConvertToInt32(Register dst,
- Register source,
- Register scratch,
- TypeInfo info,
- Label* on_not_int32) {
- if (emit_debug_code()) {
- AbortIfSmi(source);
- AbortIfNotNumber(source);
- }
- if (info.IsInteger32()) {
- cvttsd2si(dst, FieldOperand(source, HeapNumber::kValueOffset));
- } else {
- Label done;
- bool push_pop = (scratch.is(no_reg) && dst.is(source));
- ASSERT(!scratch.is(source));
- if (push_pop) {
- push(dst);
- scratch = dst;
- }
- if (scratch.is(no_reg)) scratch = dst;
- cvttsd2si(scratch, FieldOperand(source, HeapNumber::kValueOffset));
- cmp(scratch, 0x80000000u);
- if (push_pop) {
- j(not_equal, &done);
- pop(dst);
- jmp(on_not_int32);
- } else {
- j(equal, on_not_int32);
- }
-
- bind(&done);
- if (push_pop) {
- add(Operand(esp), Immediate(kPointerSize)); // Pop.
- }
- if (!scratch.is(dst)) {
- mov(dst, scratch);
- }
- }
+void MacroAssembler::LoadInstanceDescriptors(Register map,
+ Register descriptors) {
+ mov(descriptors,
+ FieldOperand(map, Map::kInstanceDescriptorsOrBitField3Offset));
+ Label not_smi;
+ JumpIfNotSmi(descriptors, ¬_smi);
+ mov(descriptors, isolate()->factory()->empty_descriptor_array());
+ bind(¬_smi);
}