Version 3.18.0
Enabled pretenuring of fast literals in high promotion mode.
Removed preparser library; link preparser executable against full V8.
Fixed set-up of intrinsic's 'constructor' properties. (Chromium issue 229445)
ES6 symbols: extended V8 API to support symbols (issue 2158).
Removed ARM support for VFP2.
Made __proto__ a real JavaScript accessor property. (issue 1949 and issue 2606)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@14304 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index da6770a..b9757fa 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -410,29 +410,46 @@
}
-// Generate StoreField code, value is passed in a0 register.
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+ Handle<GlobalObject> global,
+ Handle<Name> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> cell =
+ GlobalObject::EnsurePropertyCell(global, name);
+ ASSERT(cell->value()->IsTheHole());
+ __ li(scratch, Operand(cell));
+ __ lw(scratch,
+ FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ Branch(miss, ne, scratch, Operand(at));
+}
+
+
+// Generate StoreTransition code, value is passed in a0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label,
- Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label,
+ Label* miss_restore_name) {
// a0 : value.
Label exit;
// Check that the map of the object hasn't changed.
- CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
- : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
- DO_SMI_CHECK, mode);
+ DO_SMI_CHECK, REQUIRE_EXACT_MAP);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -440,7 +457,7 @@
}
// Check that we are allowed to write this.
- if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+ if (object->GetPrototype()->IsJSObject()) {
JSObject* holder;
// holder == object indicates that no property was found.
if (lookup->holder() != *object) {
@@ -458,12 +475,18 @@
// If no property was found, and the holder (the last object in the
// prototype chain) is in slow mode, we need to do a negative lookup on the
// holder.
- if (lookup->holder() == *object &&
- !holder->HasFastProperties() &&
- !holder->IsJSGlobalProxy() &&
- !holder->IsJSGlobalObject()) {
- GenerateDictionaryNegativeLookup(
- masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ if (lookup->holder() == *object) {
+ if (holder->IsJSGlobalObject()) {
+ GenerateCheckPropertyCell(
+ masm,
+ Handle<GlobalObject>(GlobalObject::cast(holder)),
+ name,
+ scratch1,
+ miss_restore_name);
+ } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
}
@@ -472,7 +495,7 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+ if (object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ push(receiver_reg);
@@ -485,33 +508,114 @@
return;
}
- int index;
- if (!transition.is_null()) {
- // Update the map of the object.
- __ li(scratch1, Operand(transition));
- __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+ // Update the map of the object.
+ __ li(scratch1, Operand(transition));
+ __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
- // Update the write barrier for the map field and pass the now unused
- // name_reg as scratch register.
- __ RecordWriteField(receiver_reg,
- HeapObject::kMapOffset,
- scratch1,
- name_reg,
- kRAHasNotBeenSaved,
- kDontSaveFPRegs,
- OMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- index = transition->instance_descriptors()->GetFieldIndex(
- transition->LastAdded());
- } else {
- index = lookup->GetFieldIndex().field_index();
- }
+ // Update the write barrier for the map field and pass the now unused
+ // name_reg as scratch register.
+ __ RecordWriteField(receiver_reg,
+ HeapObject::kMapOffset,
+ scratch1,
+ name_reg,
+ kRAHasNotBeenSaved,
+ kDontSaveFPRegs,
+ OMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+ int index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
// Adjust for the number of properties stored in the object. Even in the
// face of a transition we can use the old map here because the size of the
// object and the number of in-object properties is not going to change.
index -= object->map()->inobject_properties();
+ // TODO(verwaest): Share this code as a code stub.
+ if (index < 0) {
+ // Set the property straight into the object.
+ int offset = object->map()->instance_size() + (index * kPointerSize);
+ __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
+
+ // Skip updating write barrier if storing a smi.
+ __ JumpIfSmi(value_reg, &exit);
+
+ // Update the write barrier for the array address.
+ // Pass the now unused name_reg as a scratch register.
+ __ mov(name_reg, value_reg);
+ __ RecordWriteField(receiver_reg,
+ offset,
+ name_reg,
+ scratch1,
+ kRAHasNotBeenSaved,
+ kDontSaveFPRegs);
+ } else {
+ // Write to the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ // Get the properties array
+ __ lw(scratch1,
+ FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
+ __ sw(value_reg, FieldMemOperand(scratch1, offset));
+
+ // Skip updating write barrier if storing a smi.
+ __ JumpIfSmi(value_reg, &exit);
+
+ // Update the write barrier for the array address.
+ // Ok to clobber receiver_reg and name_reg, since we return.
+ __ mov(name_reg, value_reg);
+ __ RecordWriteField(scratch1,
+ offset,
+ name_reg,
+ receiver_reg,
+ kRAHasNotBeenSaved,
+ kDontSaveFPRegs);
+ }
+
+ // Return the value (register v0).
+ ASSERT(value_reg.is(a0));
+ __ bind(&exit);
+ __ mov(v0, a0);
+ __ Ret();
+}
+
+
+// Generate StoreField code, value is passed in a0 register.
+// When leaving generated code after success, the receiver_reg and name_reg
+// may be clobbered. Upon branch to miss_label, the receiver and name
+// registers have their original values.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
+ // a0 : value
+ Label exit;
+
+ // Check that the map of the object hasn't changed.
+ __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
+ DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+ // Perform global security token check if needed.
+ if (object->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
+ }
+
+ // Stub never generated for non-global objects that require access
+ // checks.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ int index = lookup->GetFieldIndex().field_index();
+
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
+ // TODO(verwaest): Share this code as a code stub.
if (index < 0) {
// Set the property straight into the object.
int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -926,26 +1030,6 @@
};
-
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
- Handle<GlobalObject> global,
- Handle<Name> name,
- Register scratch,
- Label* miss) {
- Handle<JSGlobalPropertyCell> cell =
- GlobalObject::EnsurePropertyCell(global, name);
- ASSERT(cell->value()->IsTheHole());
- __ li(scratch, Operand(cell));
- __ lw(scratch,
- FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ Branch(miss, ne, scratch, Operand(at));
-}
-
-
// Calls GenerateCheckPropertyCell for each global object in the prototype chain
// from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
@@ -975,72 +1059,12 @@
Register dst,
Register wordoffset,
Register ival,
- Register fval,
- Register scratch1,
- Register scratch2) {
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ mtc1(ival, f0);
- __ cvt_s_w(f0, f0);
- __ sll(scratch1, wordoffset, 2);
- __ addu(scratch1, dst, scratch1);
- __ swc1(f0, MemOperand(scratch1, 0));
- } else {
- // FPU is not available, do manual conversions.
-
- Label not_special, done;
- // Move sign bit from source to destination. This works because the sign
- // bit in the exponent word of the double has the same position and polarity
- // as the 2's complement sign bit in a Smi.
- ASSERT(kBinary32SignMask == 0x80000000u);
-
- __ And(fval, ival, Operand(kBinary32SignMask));
- // Negate value if it is negative.
- __ subu(scratch1, zero_reg, ival);
- __ Movn(ival, scratch1, fval);
-
- // We have -1, 0 or 1, which we treat specially. Register ival contains
- // absolute value: it is either equal to 1 (special case of -1 and 1),
- // greater than 1 (not a special case) or less than 1 (special case of 0).
- __ Branch(¬_special, gt, ival, Operand(1));
-
- // For 1 or -1 we need to or in the 0 exponent (biased).
- static const uint32_t exponent_word_for_1 =
- kBinary32ExponentBias << kBinary32ExponentShift;
-
- __ Xor(scratch1, ival, Operand(1));
- __ li(scratch2, exponent_word_for_1);
- __ or_(scratch2, fval, scratch2);
- __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
- __ Branch(&done);
-
- __ bind(¬_special);
- // Count leading zeros.
- // Gets the wrong answer for 0, but we already checked for that case above.
- Register zeros = scratch2;
- __ Clz(zeros, ival);
-
- // Compute exponent and or it into the exponent register.
- __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
- __ subu(scratch1, scratch1, zeros);
-
- __ sll(scratch1, scratch1, kBinary32ExponentShift);
- __ or_(fval, fval, scratch1);
-
- // Shift up the source chopping the top bit off.
- __ Addu(zeros, zeros, Operand(1));
- // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
- __ sllv(ival, ival, zeros);
- // And the top (top 20 bits).
- __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
- __ or_(fval, fval, scratch1);
-
- __ bind(&done);
-
- __ sll(scratch1, wordoffset, 2);
- __ addu(scratch1, dst, scratch1);
- __ sw(fval, MemOperand(scratch1, 0));
- }
+ Register scratch1) {
+ __ mtc1(ival, f0);
+ __ cvt_s_w(f0, f0);
+ __ sll(scratch1, wordoffset, 2);
+ __ addu(scratch1, dst, scratch1);
+ __ swc1(f0, MemOperand(scratch1, 0));
}
@@ -1229,7 +1253,7 @@
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+ HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
@@ -1237,13 +1261,6 @@
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
- if (!last->HasFastProperties()) {
- __ lw(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
- __ lw(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
- __ Branch(&miss, ne, scratch2(),
- Operand(isolate()->factory()->null_value()));
- }
-
HandlerFrontendFooter(success, &miss);
}
@@ -2100,11 +2117,7 @@
// -- sp[argc * 4] : receiver
// -----------------------------------
- if (!CpuFeatures::IsSupported(FPU)) {
- return Handle<Code>::null();
- }
- CpuFeatureScope scope_fpu(masm(), FPU);
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
@@ -3170,36 +3183,6 @@
}
-static bool IsElementTypeSigned(ElementsKind elements_kind) {
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- return true;
-
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_PIXEL_ELEMENTS:
- return false;
-
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- return false;
- }
- return false;
-}
-
-
static void GenerateSmiKeyCheck(MacroAssembler* masm,
Register key,
Register scratch0,
@@ -3207,36 +3190,30 @@
FPURegister double_scratch0,
FPURegister double_scratch1,
Label* fail) {
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- Label key_ok;
- // Check for smi or a smi inside a heap number. We convert the heap
- // number and check if the conversion is exact and fits into the smi
- // range.
- __ JumpIfSmi(key, &key_ok);
- __ CheckMap(key,
- scratch0,
- Heap::kHeapNumberMapRootIndex,
- fail,
- DONT_DO_SMI_CHECK);
- __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
- __ EmitFPUTruncate(kRoundToZero,
- scratch0,
- double_scratch0,
- at,
- double_scratch1,
- scratch1,
- kCheckForInexactConversion);
+ Label key_ok;
+ // Check for smi or a smi inside a heap number. We convert the heap
+ // number and check if the conversion is exact and fits into the smi
+ // range.
+ __ JumpIfSmi(key, &key_ok);
+ __ CheckMap(key,
+ scratch0,
+ Heap::kHeapNumberMapRootIndex,
+ fail,
+ DONT_DO_SMI_CHECK);
+ __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
+ __ EmitFPUTruncate(kRoundToZero,
+ scratch0,
+ double_scratch0,
+ at,
+ double_scratch1,
+ scratch1,
+ kCheckForInexactConversion);
- __ Branch(fail, ne, scratch1, Operand(zero_reg));
+ __ Branch(fail, ne, scratch1, Operand(zero_reg));
- __ SmiTagCheckOverflow(key, scratch0, scratch1);
- __ BranchOnOverflow(fail, scratch1);
- __ bind(&key_ok);
- } else {
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, fail);
- }
+ __ SmiTagCheckOverflow(key, scratch0, scratch1);
+ __ BranchOnOverflow(fail, scratch1);
+ __ bind(&key_ok);
}
@@ -3327,29 +3304,19 @@
case EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
__ SmiUntag(t0, key);
- StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
+ StoreIntAsFloat(masm, a3, t0, t1, t2);
break;
case EXTERNAL_DOUBLE_ELEMENTS:
__ sll(t8, key, 2);
__ addu(a3, a3, t8);
// a3: effective address of the double element
FloatingPointHelper::Destination destination;
- if (CpuFeatures::IsSupported(FPU)) {
- destination = FloatingPointHelper::kFPURegisters;
- } else {
- destination = FloatingPointHelper::kCoreRegisters;
- }
+ destination = FloatingPointHelper::kFPURegisters;
FloatingPointHelper::ConvertIntToDouble(
masm, t1, destination,
f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
t0, f2); // These are: scratch2, single_scratch.
- if (destination == FloatingPointHelper::kFPURegisters) {
- CpuFeatureScope scope(masm, FPU);
- __ sdc1(f0, MemOperand(a3, 0));
- } else {
- __ sw(t2, MemOperand(a3, 0));
- __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
- }
+ __ sdc1(f0, MemOperand(a3, 0));
break;
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
@@ -3381,232 +3348,59 @@
// +/-Infinity into integer arrays basically undefined. For more
// reproducible behavior, convert these to zero.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
+ __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- __ cvt_s_d(f0, f0);
- __ sll(t8, key, 1);
- __ addu(t8, a3, t8);
- __ swc1(f0, MemOperand(t8, 0));
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- __ sll(t8, key, 2);
- __ addu(t8, a3, t8);
- __ sdc1(f0, MemOperand(t8, 0));
- } else {
- __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
-
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ srl(t8, key, 1);
- __ addu(t8, a3, t8);
- __ sb(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ addu(t8, a3, key);
- __ sh(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ sll(t8, key, 1);
- __ addu(t8, a3, t8);
- __ sw(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
- }
-
- // Entry registers are intact, a0 holds the value
- // which is the return value.
- __ mov(v0, a0);
- __ Ret();
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+ __ cvt_s_d(f0, f0);
+ __ sll(t8, key, 1);
+ __ addu(t8, a3, t8);
+ __ swc1(f0, MemOperand(t8, 0));
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
+ __ sll(t8, key, 2);
+ __ addu(t8, a3, t8);
+ __ sdc1(f0, MemOperand(t8, 0));
} else {
- // FPU is not available, do manual conversions.
+ __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
- __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
- __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
-
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- Label done, nan_or_infinity_or_zero;
- static const int kMantissaInHiWordShift =
- kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
- static const int kMantissaInLoWordShift =
- kBitsPerInt - kMantissaInHiWordShift;
-
- // Test for all special exponent values: zeros, subnormal numbers, NaNs
- // and infinities. All these should be converted to 0.
- __ li(t5, HeapNumber::kExponentMask);
- __ and_(t6, t3, t5);
- __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
-
- __ xor_(t1, t6, t5);
- __ li(t2, kBinary32ExponentMask);
- __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
- __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
-
- // Rebias exponent.
- __ srl(t6, t6, HeapNumber::kExponentShift);
- __ Addu(t6,
- t6,
- Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
-
- __ li(t1, Operand(kBinary32MaxExponent));
- __ Slt(t1, t1, t6);
- __ And(t2, t3, Operand(HeapNumber::kSignMask));
- __ Or(t2, t2, Operand(kBinary32ExponentMask));
- __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
- __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
-
- __ Slt(t1, t6, Operand(kBinary32MinExponent));
- __ And(t2, t3, Operand(HeapNumber::kSignMask));
- __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
- __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
-
- __ And(t7, t3, Operand(HeapNumber::kSignMask));
- __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
- __ sll(t3, t3, kMantissaInHiWordShift);
- __ or_(t7, t7, t3);
- __ srl(t4, t4, kMantissaInLoWordShift);
- __ or_(t7, t7, t4);
- __ sll(t6, t6, kBinary32ExponentShift);
- __ or_(t3, t7, t6);
-
- __ bind(&done);
- __ sll(t9, key, 1);
- __ addu(t9, a3, t9);
- __ sw(t3, MemOperand(t9, 0));
-
- // Entry registers are intact, a0 holds the value which is the return
- // value.
- __ mov(v0, a0);
- __ Ret();
-
- __ bind(&nan_or_infinity_or_zero);
- __ And(t7, t3, Operand(HeapNumber::kSignMask));
- __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
- __ or_(t6, t6, t7);
- __ sll(t3, t3, kMantissaInHiWordShift);
- __ or_(t6, t6, t3);
- __ srl(t4, t4, kMantissaInLoWordShift);
- __ or_(t3, t6, t4);
- __ Branch(&done);
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- __ sll(t8, key, 2);
- __ addu(t8, a3, t8);
- // t8: effective address of destination element.
- __ sw(t4, MemOperand(t8, 0));
- __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
- __ mov(v0, a0);
- __ Ret();
- } else {
- bool is_signed_type = IsElementTypeSigned(elements_kind);
- int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
- int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
-
- Label done, sign;
-
- // Test for all special exponent values: zeros, subnormal numbers, NaNs
- // and infinities. All these should be converted to 0.
- __ li(t5, HeapNumber::kExponentMask);
- __ and_(t6, t3, t5);
- __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
- __ Branch(&done, eq, t6, Operand(zero_reg));
-
- __ xor_(t2, t6, t5);
- __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
- __ Branch(&done, eq, t6, Operand(t5));
-
- // Unbias exponent.
- __ srl(t6, t6, HeapNumber::kExponentShift);
- __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
- // If exponent is negative then result is 0.
- __ slt(t2, t6, zero_reg);
- __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
- __ Branch(&done, lt, t6, Operand(zero_reg));
-
- // If exponent is too big then result is minimal value.
- __ slti(t1, t6, meaningfull_bits - 1);
- __ li(t2, min_value);
- __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
- __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
-
- __ And(t5, t3, Operand(HeapNumber::kSignMask));
- __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
- __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
-
- __ li(t9, HeapNumber::kMantissaBitsInTopWord);
- __ subu(t6, t9, t6);
- __ slt(t1, t6, zero_reg);
- __ srlv(t2, t3, t6);
- __ Movz(t3, t2, t1); // Only if t6 is positive.
- __ Branch(&sign, ge, t6, Operand(zero_reg));
-
- __ subu(t6, zero_reg, t6);
- __ sllv(t3, t3, t6);
- __ li(t9, meaningfull_bits);
- __ subu(t6, t9, t6);
- __ srlv(t4, t4, t6);
- __ or_(t3, t3, t4);
-
- __ bind(&sign);
- __ subu(t2, t3, zero_reg);
- __ Movz(t3, t2, t5); // Only if t5 is zero.
-
- __ bind(&done);
-
- // Result is in t3.
- // This switch block should be exactly the same as above (FPU mode).
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ srl(t8, key, 1);
- __ addu(t8, a3, t8);
- __ sb(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ addu(t8, a3, key);
- __ sh(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ sll(t8, key, 1);
- __ addu(t8, a3, t8);
- __ sw(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
+ switch (elements_kind) {
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ __ srl(t8, key, 1);
+ __ addu(t8, a3, t8);
+ __ sb(t3, MemOperand(t8, 0));
+ break;
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ __ addu(t8, a3, key);
+ __ sh(t3, MemOperand(t8, 0));
+ break;
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ __ sll(t8, key, 1);
+ __ addu(t8, a3, t8);
+ __ sw(t3, MemOperand(t8, 0));
+ break;
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ UNREACHABLE();
+ break;
}
}
+
+ // Entry registers are intact, a0 holds the value
+ // which is the return value.
+ __ mov(v0, a0);
+ __ Ret();
}
// Slow case, key and receiver still in a0 and a1.