| Index: src/ia32/macro-assembler-ia32.cc
|
| ===================================================================
|
| --- src/ia32/macro-assembler-ia32.cc (revision 8618)
|
| +++ src/ia32/macro-assembler-ia32.cc (working copy)
|
| @@ -205,9 +205,7 @@
|
|
|
| // Skip barrier if writing a smi.
|
| if (smi_check == INLINE_SMI_CHECK) {
|
| - ASSERT_EQ(0, kSmiTag);
|
| - test(value, Immediate(kSmiTagMask));
|
| - j(zero, &done, Label::kNear);
|
| + JumpIfSmi(value, &done, Label::kNear);
|
| }
|
|
|
| // Although the object register is tagged, the offset is relative to the start
|
| @@ -269,9 +267,7 @@
|
|
|
| if (smi_check == INLINE_SMI_CHECK) {
|
| // Skip barrier if writing a smi.
|
| - ASSERT_EQ(0, kSmiTag);
|
| - test(value, Immediate(kSmiTagMask));
|
| - j(zero, &done, Label::kNear);
|
| + JumpIfSmi(value, &done, Label::kNear);
|
| }
|
|
|
| CheckPageFlag(value,
|
| @@ -366,6 +362,16 @@
|
| }
|
|
|
|
|
| +void MacroAssembler::CheckFastElements(Register map,
|
| + Label* fail,
|
| + Label::Distance distance) {
|
| + STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
|
| + cmpb(FieldOperand(map, Map::kBitField2Offset),
|
| + Map::kMaximumBitField2FastElementValue);
|
| + j(above, fail, distance);
|
| +}
|
| +
|
| +
|
| void MacroAssembler::CheckMap(Register obj,
|
| Handle<Map> map,
|
| Label* fail,
|
| @@ -417,8 +423,9 @@
|
| Register scratch,
|
| Label* fail) {
|
| movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset));
|
| - sub(Operand(scratch), Immediate(FIRST_JS_OBJECT_TYPE));
|
| - cmp(scratch, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
|
| + sub(Operand(scratch), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
| + cmp(scratch,
|
| + LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
| j(above, fail);
|
| }
|
|
|
| @@ -440,8 +447,7 @@
|
|
|
| void MacroAssembler::AbortIfNotNumber(Register object) {
|
| Label ok;
|
| - test(object, Immediate(kSmiTagMask));
|
| - j(zero, &ok);
|
| + JumpIfSmi(object, &ok);
|
| cmp(FieldOperand(object, HeapObject::kMapOffset),
|
| isolate()->factory()->heap_number_map());
|
| Assert(equal, "Operand not a number");
|
| @@ -813,6 +819,104 @@
|
| }
|
|
|
|
|
| +void MacroAssembler::LoadFromNumberDictionary(Label* miss,
|
| + Register elements,
|
| + Register key,
|
| + Register r0,
|
| + Register r1,
|
| + Register r2,
|
| + Register result) {
|
| + // Register use:
|
| + //
|
| + // elements - holds the slow-case elements of the receiver and is unchanged.
|
| + //
|
| + // key - holds the smi key on entry and is unchanged.
|
| + //
|
| + // Scratch registers:
|
| + //
|
| + // r0 - holds the untagged key on entry and holds the hash once computed.
|
| + //
|
| + // r1 - used to hold the capacity mask of the dictionary
|
| + //
|
| + // r2 - used for the index into the dictionary.
|
| + //
|
| + // result - holds the result on exit if the load succeeds and we fall through.
|
| +
|
| + Label done;
|
| +
|
| + // Compute the hash code from the untagged key. This must be kept in sync
|
| + // with ComputeIntegerHash in utils.h.
|
| + //
|
| + // hash = ~hash + (hash << 15);
|
| + mov(r1, r0);
|
| + not_(r0);
|
| + shl(r1, 15);
|
| + add(r0, Operand(r1));
|
| + // hash = hash ^ (hash >> 12);
|
| + mov(r1, r0);
|
| + shr(r1, 12);
|
| + xor_(r0, Operand(r1));
|
| + // hash = hash + (hash << 2);
|
| + lea(r0, Operand(r0, r0, times_4, 0));
|
| + // hash = hash ^ (hash >> 4);
|
| + mov(r1, r0);
|
| + shr(r1, 4);
|
| + xor_(r0, Operand(r1));
|
| + // hash = hash * 2057;
|
| + imul(r0, r0, 2057);
|
| + // hash = hash ^ (hash >> 16);
|
| + mov(r1, r0);
|
| + shr(r1, 16);
|
| + xor_(r0, Operand(r1));
|
| +
|
| + // Compute capacity mask.
|
| + mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
|
| + shr(r1, kSmiTagSize); // convert smi to int
|
| + dec(r1);
|
| +
|
| + // Generate an unrolled loop that performs a few probes before giving up.
|
| + const int kProbes = 4;
|
| + for (int i = 0; i < kProbes; i++) {
|
| + // Use r2 for index calculations and keep the hash intact in r0.
|
| + mov(r2, r0);
|
| + // Compute the masked index: (hash + i + i * i) & mask.
|
| + if (i > 0) {
|
| + add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
|
| + }
|
| + and_(r2, Operand(r1));
|
| +
|
| + // Scale the index by multiplying by the entry size.
|
| + ASSERT(NumberDictionary::kEntrySize == 3);
|
| + lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
|
| +
|
| + // Check if the key matches.
|
| + cmp(key, FieldOperand(elements,
|
| + r2,
|
| + times_pointer_size,
|
| + NumberDictionary::kElementsStartOffset));
|
| + if (i != (kProbes - 1)) {
|
| + j(equal, &done);
|
| + } else {
|
| + j(not_equal, miss);
|
| + }
|
| + }
|
| +
|
| + bind(&done);
|
| + // Check that the value is a normal propety.
|
| + const int kDetailsOffset =
|
| + NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
|
| + ASSERT_EQ(NORMAL, 0);
|
| + test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
|
| + Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
|
| + j(not_zero, miss);
|
| +
|
| + // Get the value at the masked, scaled index.
|
| + const int kValueOffset =
|
| + NumberDictionary::kElementsStartOffset + kPointerSize;
|
| + mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
|
| +}
|
| +
|
| +
|
| void MacroAssembler::LoadAllocationTopHelper(Register result,
|
| Register scratch,
|
| AllocationFlags flags) {
|
| @@ -1252,8 +1356,7 @@
|
| Register scratch,
|
| Label* miss) {
|
| // Check that the receiver isn't a smi.
|
| - test(function, Immediate(kSmiTagMask));
|
| - j(zero, miss);
|
| + JumpIfSmi(function, miss);
|
|
|
| // Check that the function really is a function.
|
| CmpObjectType(function, JS_FUNCTION_TYPE, result);
|
| @@ -1492,32 +1595,30 @@
|
| }
|
|
|
|
|
| -void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) {
|
| +void MacroAssembler::PrepareCallApiFunction(int argc) {
|
| if (kReturnHandlesDirectly) {
|
| EnterApiExitFrame(argc);
|
| // When handles are returned directly we don't have to allocate extra
|
| // space for and pass an out parameter.
|
| + if (emit_debug_code()) {
|
| + mov(esi, Immediate(BitCast<int32_t>(kZapValue)));
|
| + }
|
| } else {
|
| // We allocate two additional slots: return value and pointer to it.
|
| EnterApiExitFrame(argc + 2);
|
|
|
| // The argument slots are filled as follows:
|
| //
|
| - // n + 1: output cell
|
| + // n + 1: output slot
|
| // n: arg n
|
| // ...
|
| // 1: arg1
|
| - // 0: pointer to the output cell
|
| - //
|
| - // Note that this is one more "argument" than the function expects
|
| - // so the out cell will have to be popped explicitly after returning
|
| - // from the function. The out cell contains Handle.
|
| + // 0: pointer to the output slot
|
|
|
| - // pointer to out cell.
|
| - lea(scratch, Operand(esp, (argc + 1) * kPointerSize));
|
| - mov(Operand(esp, 0 * kPointerSize), scratch); // output.
|
| + lea(esi, Operand(esp, (argc + 1) * kPointerSize));
|
| + mov(Operand(esp, 0 * kPointerSize), esi);
|
| if (emit_debug_code()) {
|
| - mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0)); // out cell.
|
| + mov(Operand(esi, 0), Immediate(0));
|
| }
|
| }
|
| }
|
| @@ -1541,9 +1642,9 @@
|
| call(function->address(), RelocInfo::RUNTIME_ENTRY);
|
|
|
| if (!kReturnHandlesDirectly) {
|
| - // The returned value is a pointer to the handle holding the result.
|
| - // Dereference this to get to the location.
|
| - mov(eax, Operand(eax, 0));
|
| + // PrepareCallApiFunction saved pointer to the output slot into
|
| + // callee-save register esi.
|
| + mov(eax, Operand(esi, 0));
|
| }
|
|
|
| Label empty_handle;
|
| @@ -1777,7 +1878,8 @@
|
| void MacroAssembler::InvokeFunction(JSFunction* function,
|
| const ParameterCount& actual,
|
| InvokeFlag flag,
|
| - const CallWrapper& call_wrapper) {
|
| + const CallWrapper& call_wrapper,
|
| + CallKind call_kind) {
|
| ASSERT(function->is_compiled());
|
| // Get the function and setup the context.
|
| mov(edi, Immediate(Handle<JSFunction>(function)));
|
| @@ -1789,11 +1891,11 @@
|
| // 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, call_wrapper);
|
| + expected, actual, flag, call_wrapper, call_kind);
|
| } else {
|
| Handle<Code> code(function->code());
|
| InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET,
|
| - flag, call_wrapper);
|
| + flag, call_wrapper, call_kind);
|
| }
|
| }
|
|
|
| @@ -1810,7 +1912,7 @@
|
| ParameterCount expected(0);
|
| GetBuiltinFunction(edi, id);
|
| InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
|
| - expected, expected, flag, call_wrapper);
|
| + expected, expected, flag, call_wrapper, CALL_AS_METHOD);
|
| }
|
|
|
| void MacroAssembler::GetBuiltinFunction(Register target,
|
| @@ -1834,12 +1936,9 @@
|
| void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
|
| if (context_chain_length > 0) {
|
| // Move up the chain of contexts to the context containing the slot.
|
| - mov(dst, Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| - // Load the function context (which is the incoming, outer context).
|
| - mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
|
| + mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX)));
|
| for (int i = 1; i < context_chain_length; i++) {
|
| - mov(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| - mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
|
| + mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
|
| }
|
| } else {
|
| // Slot is in the current function context. Move it into the
|
| @@ -1848,14 +1947,14 @@
|
| mov(dst, esi);
|
| }
|
|
|
| - // We should not have found a 'with' context by walking the context chain
|
| + // We should not have found a with context by walking the context chain
|
| // (i.e., the static scope chain and runtime context chain do not agree).
|
| // A variable occurring in such a scope should have slot type LOOKUP and
|
| // not CONTEXT.
|
| if (emit_debug_code()) {
|
| - cmp(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
|
| - Check(equal, "Yo dawg, I heard you liked function contexts "
|
| - "so I put function contexts in all your contexts");
|
| + cmp(FieldOperand(dst, HeapObject::kMapOffset),
|
| + isolate()->factory()->with_context_map());
|
| + Check(not_equal, "Variable resolved to with context.");
|
| }
|
| }
|
|
|
| @@ -2134,8 +2233,7 @@
|
| ASSERT_EQ(0, kSmiTag);
|
| mov(scratch1, Operand(object1));
|
| and_(scratch1, Operand(object2));
|
| - test(scratch1, Immediate(kSmiTagMask));
|
| - j(zero, failure);
|
| + JumpIfSmi(scratch1, failure);
|
|
|
| // Load instance type for both strings.
|
| mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
|
|
|