Upgrade to V8 3.5
Merge V8 3.5.10.24
Simple merge required updates to makefiles only.
Bug: 5688872
Change-Id: I0acdb9a1a53919d84e9a7525308e8371739d2f06
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index 51642e0..28ac557 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -780,10 +780,10 @@
void Assembler::next(Label* L) {
ASSERT(L->is_linked());
int link = target_at(L->pos());
- ASSERT(link > 0 || link == kEndOfChain);
if (link == kEndOfChain) {
L->Unuse();
- } else if (link > 0) {
+ } else {
+ ASSERT(link >= 0);
L->link_to(link);
}
}
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index a16cd80..e5077be 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -127,38 +127,38 @@
const Register no_reg = { -1 };
-const Register zero_reg = { 0 };
-const Register at = { 1 };
-const Register v0 = { 2 };
-const Register v1 = { 3 };
-const Register a0 = { 4 };
+const Register zero_reg = { 0 }; // Always zero.
+const Register at = { 1 }; // at: Reserved for synthetic instructions.
+const Register v0 = { 2 }; // v0, v1: Used when returning multiple values
+const Register v1 = { 3 }; // from subroutines.
+const Register a0 = { 4 }; // a0 - a4: Used to pass non-FP parameters.
const Register a1 = { 5 };
const Register a2 = { 6 };
const Register a3 = { 7 };
-const Register t0 = { 8 };
-const Register t1 = { 9 };
-const Register t2 = { 10 };
+const Register t0 = { 8 }; // t0 - t9: Can be used without reservation, act
+const Register t1 = { 9 }; // as temporary registers and are allowed to
+const Register t2 = { 10 }; // be destroyed by subroutines.
const Register t3 = { 11 };
const Register t4 = { 12 };
const Register t5 = { 13 };
const Register t6 = { 14 };
const Register t7 = { 15 };
-const Register s0 = { 16 };
-const Register s1 = { 17 };
-const Register s2 = { 18 };
-const Register s3 = { 19 };
-const Register s4 = { 20 };
+const Register s0 = { 16 }; // s0 - s7: Subroutine register variables.
+const Register s1 = { 17 }; // Subroutines that write to these registers
+const Register s2 = { 18 }; // must restore their values before exiting so
+const Register s3 = { 19 }; // that the caller can expect the values to be
+const Register s4 = { 20 }; // preserved.
const Register s5 = { 21 };
const Register s6 = { 22 };
const Register s7 = { 23 };
const Register t8 = { 24 };
const Register t9 = { 25 };
-const Register k0 = { 26 };
-const Register k1 = { 27 };
-const Register gp = { 28 };
-const Register sp = { 29 };
-const Register s8_fp = { 30 };
-const Register ra = { 31 };
+const Register k0 = { 26 }; // k0, k1: Reserved for system calls and
+const Register k1 = { 27 }; // interrupt handlers.
+const Register gp = { 28 }; // gp: Reserved.
+const Register sp = { 29 }; // sp: Stack pointer.
+const Register s8_fp = { 30 }; // fp: Frame pointer.
+const Register ra = { 31 }; // ra: Return address pointer.
int ToNumber(Register reg);
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index d89d3e5..9385f2f 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -2506,7 +2506,7 @@
CpuFeatures::Scope scope(FPU);
__ mtc1(a2, f0);
if (op_ == Token::SHR) {
- __ Cvt_d_uw(f0, f0);
+ __ Cvt_d_uw(f0, f0, f22);
} else {
__ cvt_d_w(f0, f0);
}
@@ -2920,7 +2920,7 @@
} else {
// The result must be interpreted as an unsigned 32-bit integer.
__ mtc1(a2, double_scratch);
- __ Cvt_d_uw(double_scratch, double_scratch);
+ __ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
}
// Store the result.
@@ -3693,10 +3693,10 @@
// args
// Save callee saved registers on the stack.
- __ MultiPush((kCalleeSaved | ra.bit()) & ~sp.bit());
+ __ MultiPush(kCalleeSaved | ra.bit());
// Load argv in s0 register.
- __ lw(s0, MemOperand(sp, kNumCalleeSaved * kPointerSize +
+ __ lw(s0, MemOperand(sp, (kNumCalleeSaved + 1) * kPointerSize +
StandardFrameConstants::kCArgsSlotsSize));
// We build an EntryFrame.
@@ -3830,7 +3830,7 @@
__ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
// Restore callee saved registers from the stack.
- __ MultiPop((kCalleeSaved | ra.bit()) & ~sp.bit());
+ __ MultiPop(kCalleeSaved | ra.bit());
// Return.
__ Jump(ra);
}
@@ -4517,6 +4517,9 @@
__ Addu(a2, a2, Operand(RegExpImpl::kLastMatchOverhead));
__ sra(at, a0, kSmiTagSize); // Untag length for comparison.
__ Branch(&runtime, gt, a2, Operand(at));
+
+ // Reset offset for possibly sliced string.
+ __ mov(t0, zero_reg);
// subject: Subject string
// regexp_data: RegExp data (FixedArray)
// Check the representation and encoding of the subject string.
@@ -4524,29 +4527,41 @@
__ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
__ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
// First check for flat string.
- __ And(at, a0, Operand(kIsNotStringMask | kStringRepresentationMask));
+ __ And(a1, a0, Operand(kIsNotStringMask | kStringRepresentationMask));
STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
- __ Branch(&seq_string, eq, at, Operand(zero_reg));
+ __ Branch(&seq_string, eq, a1, Operand(zero_reg));
// subject: Subject string
// a0: instance type if Subject string
// regexp_data: RegExp data (FixedArray)
- // Check for flat cons string.
+ // Check for flat cons string or sliced string.
// A flat cons string is a cons string where the second part is the empty
// string. In that case the subject string is just the first part of the cons
// string. Also in this case the first part of the cons string is known to be
// a sequential string or an external string.
- STATIC_ASSERT(kExternalStringTag != 0);
- STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0);
- __ And(at, a0, Operand(kIsNotStringMask | kExternalStringTag));
- __ Branch(&runtime, ne, at, Operand(zero_reg));
+ // In the case of a sliced string its offset has to be taken into account.
+ Label cons_string, check_encoding;
+ STATIC_ASSERT(kConsStringTag < kExternalStringTag);
+ STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
+ __ Branch(&cons_string, lt, a1, Operand(kExternalStringTag));
+ __ Branch(&runtime, eq, a1, Operand(kExternalStringTag));
+
+ // String is sliced.
+ __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset));
+ __ sra(t0, t0, kSmiTagSize);
+ __ lw(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
+ // t5: offset of sliced string, smi-tagged.
+ __ jmp(&check_encoding);
+ // String is a cons string, check whether it is flat.
+ __ bind(&cons_string);
__ lw(a0, FieldMemOperand(subject, ConsString::kSecondOffset));
__ LoadRoot(a1, Heap::kEmptyStringRootIndex);
__ Branch(&runtime, ne, a0, Operand(a1));
__ lw(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
+ // Is first part of cons or parent of slice a flat string?
+ __ bind(&check_encoding);
__ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
__ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
- // Is first part a flat string?
STATIC_ASSERT(kSeqStringTag == 0);
__ And(at, a0, Operand(kStringRepresentationMask));
__ Branch(&runtime, ne, at, Operand(zero_reg));
@@ -4562,8 +4577,8 @@
__ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ascii.
__ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset));
__ sra(a3, a0, 2); // a3 is 1 for ascii, 0 for UC16 (usyed below).
- __ lw(t0, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset));
- __ movz(t9, t0, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset.
+ __ lw(t1, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset));
+ __ movz(t9, t1, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset.
// Check that the irregexp code has been generated for the actual string
// encoding. If it has, the field contains a code object otherwise it contains
@@ -4630,23 +4645,32 @@
// For arguments 4 and 3 get string length, calculate start of string data
// and calculate the shift of the index (0 for ASCII and 1 for two byte).
- __ lw(a0, FieldMemOperand(subject, String::kLengthOffset));
- __ sra(a0, a0, kSmiTagSize);
STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
- __ Addu(t0, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+ __ Addu(t2, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
__ Xor(a3, a3, Operand(1)); // 1 for 2-byte str, 0 for 1-byte.
- // Argument 4 (a3): End of string data
- // Argument 3 (a2): Start of string data
+ // Load the length from the original subject string from the previous stack
+ // frame. Therefore we have to use fp, which points exactly to two pointer
+ // sizes below the previous sp. (Because creating a new stack frame pushes
+ // the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
+ __ lw(a0, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
+ // If slice offset is not 0, load the length from the original sliced string.
+ // Argument 4, a3: End of string data
+ // Argument 3, a2: Start of string data
+ // Prepare start and end index of the input.
+ __ sllv(t1, t0, a3);
+ __ addu(t0, t2, t1);
__ sllv(t1, a1, a3);
__ addu(a2, t0, t1);
- __ sllv(t1, a0, a3);
- __ addu(a3, t0, t1);
+ __ lw(t2, FieldMemOperand(a0, String::kLengthOffset));
+ __ sra(t2, t2, kSmiTagSize);
+ __ sllv(t1, t2, a3);
+ __ addu(a3, t0, t1);
// Argument 2 (a1): Previous index.
// Already there
// Argument 1 (a0): Subject string.
- __ mov(a0, subject);
+ // Already there
// Locate the code entry and call it.
__ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
@@ -4663,11 +4687,14 @@
// Check the result.
Label success;
- __ Branch(&success, eq, v0, Operand(NativeRegExpMacroAssembler::SUCCESS));
+ __ Branch(&success, eq,
+ subject, Operand(NativeRegExpMacroAssembler::SUCCESS));
Label failure;
- __ Branch(&failure, eq, v0, Operand(NativeRegExpMacroAssembler::FAILURE));
+ __ Branch(&failure, eq,
+ subject, Operand(NativeRegExpMacroAssembler::FAILURE));
// If not exception it can only be retry. Handle that in the runtime system.
- __ Branch(&runtime, ne, v0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
+ __ Branch(&runtime, ne,
+ subject, Operand(NativeRegExpMacroAssembler::EXCEPTION));
// Result must now be exception. If there is no pending exception already a
// stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system.
@@ -4678,16 +4705,16 @@
__ li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address,
masm->isolate())));
__ lw(v0, MemOperand(a2, 0));
- __ Branch(&runtime, eq, v0, Operand(a1));
+ __ Branch(&runtime, eq, subject, Operand(a1));
__ sw(a1, MemOperand(a2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable.
__ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
Label termination_exception;
- __ Branch(&termination_exception, eq, v0, Operand(a0));
+ __ Branch(&termination_exception, eq, subject, Operand(a0));
- __ Throw(a0); // Expects thrown value in v0.
+ __ Throw(subject); // Expects thrown value in v0.
__ bind(&termination_exception);
__ ThrowUncatchable(TERMINATION, v0); // Expects thrown value in v0.
@@ -4963,6 +4990,7 @@
Label flat_string;
Label ascii_string;
Label got_char_code;
+ Label sliced_string;
ASSERT(!t0.is(scratch_));
ASSERT(!t0.is(index_));
@@ -4996,23 +5024,37 @@
__ Branch(&flat_string, eq, t0, Operand(zero_reg));
// Handle non-flat strings.
- __ And(t0, result_, Operand(kIsConsStringMask));
- __ Branch(&call_runtime_, eq, t0, Operand(zero_reg));
+ __ And(result_, result_, Operand(kStringRepresentationMask));
+ STATIC_ASSERT(kConsStringTag < kExternalStringTag);
+ STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
+ __ Branch(&sliced_string, gt, result_, Operand(kExternalStringTag));
+ __ Branch(&call_runtime_, eq, result_, Operand(kExternalStringTag));
// ConsString.
// Check whether the right hand side is the empty string (i.e. if
// this is really a flat string in a cons string). If that is not
// the case we would rather go to the runtime system now to flatten
// the string.
+ Label assure_seq_string;
__ lw(result_, FieldMemOperand(object_, ConsString::kSecondOffset));
__ LoadRoot(t0, Heap::kEmptyStringRootIndex);
__ Branch(&call_runtime_, ne, result_, Operand(t0));
// Get the first of the two strings and load its instance type.
__ lw(object_, FieldMemOperand(object_, ConsString::kFirstOffset));
+ __ jmp(&assure_seq_string);
+
+ // SlicedString, unpack and add offset.
+ __ bind(&sliced_string);
+ __ lw(result_, FieldMemOperand(object_, SlicedString::kOffsetOffset));
+ __ addu(scratch_, scratch_, result_);
+ __ lw(object_, FieldMemOperand(object_, SlicedString::kParentOffset));
+
+ // Assure that we are dealing with a sequential string. Go to runtime if not.
+ __ bind(&assure_seq_string);
__ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
__ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
- // If the first cons component is also non-flat, then go to runtime.
+ // Check that parent is not an external string. Go to runtime otherwise.
STATIC_ASSERT(kSeqStringTag == 0);
__ And(t0, result_, Operand(kStringRepresentationMask));
@@ -5583,6 +5625,11 @@
Register to = t2;
Register from = t3;
+ if (FLAG_string_slices) {
+ __ nop(); // Jumping as first instruction would crash the code generation.
+ __ jmp(&sub_string_runtime);
+ }
+
// Check bounds and smi-ness.
__ lw(to, MemOperand(sp, kToOffset));
__ lw(from, MemOperand(sp, kFromOffset));
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index 9a19aba..18b6231 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -39,7 +39,7 @@
namespace internal {
-int Deoptimizer::table_entry_size_ = 10;
+const int Deoptimizer::table_entry_size_ = 10;
int Deoptimizer::patch_size() {
diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h
index 2e720fb..1899843 100644
--- a/src/mips/frames-mips.h
+++ b/src/mips/frames-mips.h
@@ -59,10 +59,10 @@
// Saved temporaries.
1 << 16 | 1 << 17 | 1 << 18 | 1 << 19 |
1 << 20 | 1 << 21 | 1 << 22 | 1 << 23 |
- // gp, sp, fp.
- 1 << 28 | 1 << 29 | 1 << 30;
+ // fp.
+ 1 << 30;
-static const int kNumCalleeSaved = 11;
+static const int kNumCalleeSaved = 9;
// Number of registers for which space is reserved in safepoints. Must be a
@@ -121,10 +121,11 @@
class StackHandlerConstants : public AllStatic {
public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kStateOffset = 1 * kPointerSize;
- static const int kFPOffset = 2 * kPointerSize;
- static const int kPCOffset = 3 * kPointerSize;
+ static const int kNextOffset = 0 * kPointerSize;
+ static const int kStateOffset = 1 * kPointerSize;
+ static const int kContextOffset = 2 * kPointerSize;
+ static const int kFPOffset = 3 * kPointerSize;
+ static const int kPCOffset = 4 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize;
};
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 7834273..d3f8922 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -55,7 +55,6 @@
static unsigned GetPropertyId(Property* property) {
- if (property->is_synthetic()) return AstNode::kNoNumber;
return property->id();
}
@@ -697,109 +696,77 @@
Comment cmnt(masm_, "[ Declaration");
ASSERT(variable != NULL); // Must have been resolved.
Slot* slot = variable->AsSlot();
- Property* prop = variable->AsProperty();
-
- if (slot != NULL) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- if (mode == Variable::CONST) {
- __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
- __ sw(t0, MemOperand(fp, SlotOffset(slot)));
- } else if (function != NULL) {
- VisitForAccumulatorValue(function);
- __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
- }
- break;
-
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
- // The variable in the decl always resides in the current function
- // context.
- ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
- if (FLAG_debug_code) {
- // Check that we're not inside a with or catch context.
- __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
- __ LoadRoot(t0, Heap::kWithContextMapRootIndex);
- __ Check(ne, "Declaration in with context.",
- a1, Operand(t0));
- __ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
- __ Check(ne, "Declaration in catch context.",
- a1, Operand(t0));
- }
- if (mode == Variable::CONST) {
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ sw(at, ContextOperand(cp, slot->index()));
- // No write barrier since the_hole_value is in old space.
- } else if (function != NULL) {
- VisitForAccumulatorValue(function);
- __ sw(result_register(), ContextOperand(cp, slot->index()));
- int offset = Context::SlotOffset(slot->index());
- // We know that we have written a function, which is not a smi.
- __ mov(a1, cp);
- __ RecordWrite(a1, Operand(offset), a2, result_register());
- }
- break;
-
- case Slot::LOOKUP: {
- __ li(a2, Operand(variable->name()));
- // Declaration nodes are always introduced in one of two modes.
- ASSERT(mode == Variable::VAR ||
- mode == Variable::CONST);
- PropertyAttributes attr =
- (mode == Variable::VAR) ? NONE : READ_ONLY;
- __ li(a1, Operand(Smi::FromInt(attr)));
- // Push initial value, if any.
- // Note: For variables we must not push an initial value (such as
- // 'undefined') because we may have a (legal) redeclaration and we
- // must not destroy the current value.
- if (mode == Variable::CONST) {
- __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
- __ Push(cp, a2, a1, a0);
- } else if (function != NULL) {
- __ Push(cp, a2, a1);
- // Push initial value for function declaration.
- VisitForStackValue(function);
- } else {
- ASSERT(Smi::FromInt(0) == 0);
- // No initial value!
- __ mov(a0, zero_reg); // Operand(Smi::FromInt(0)));
- __ Push(cp, a2, a1, a0);
- }
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
- break;
+ ASSERT(slot != NULL);
+ switch (slot->type()) {
+ case Slot::PARAMETER:
+ case Slot::LOCAL:
+ if (mode == Variable::CONST) {
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ sw(t0, MemOperand(fp, SlotOffset(slot)));
+ } else if (function != NULL) {
+ VisitForAccumulatorValue(function);
+ __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
}
- }
+ break;
- } else if (prop != NULL) {
- // A const declaration aliasing a parameter is an illegal redeclaration.
- ASSERT(mode != Variable::CONST);
- if (function != NULL) {
- // We are declaring a function that rewrites to a property.
- // Use (keyed) IC to set the initial value. We cannot visit the
- // rewrite because it's shared and we risk recording duplicate AST
- // IDs for bailouts from optimized code.
- ASSERT(prop->obj()->AsVariableProxy() != NULL);
- { AccumulatorValueContext for_object(this);
- EmitVariableLoad(prop->obj()->AsVariableProxy());
+ case Slot::CONTEXT:
+ // We bypass the general EmitSlotSearch because we know more about
+ // this specific context.
+
+ // The variable in the decl always resides in the current function
+ // context.
+ ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
+ if (FLAG_debug_code) {
+ // Check that we're not inside a with or catch context.
+ __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
+ __ LoadRoot(t0, Heap::kWithContextMapRootIndex);
+ __ Check(ne, "Declaration in with context.",
+ a1, Operand(t0));
+ __ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
+ __ Check(ne, "Declaration in catch context.",
+ a1, Operand(t0));
}
+ if (mode == Variable::CONST) {
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ sw(at, ContextOperand(cp, slot->index()));
+ // No write barrier since the_hole_value is in old space.
+ } else if (function != NULL) {
+ VisitForAccumulatorValue(function);
+ __ sw(result_register(), ContextOperand(cp, slot->index()));
+ int offset = Context::SlotOffset(slot->index());
+ // We know that we have written a function, which is not a smi.
+ __ mov(a1, cp);
+ __ RecordWrite(a1, Operand(offset), a2, result_register());
+ }
+ break;
- __ push(result_register());
- VisitForAccumulatorValue(function);
- __ mov(a0, result_register());
- __ pop(a2);
-
- ASSERT(prop->key()->AsLiteral() != NULL &&
- prop->key()->AsLiteral()->handle()->IsSmi());
- __ li(a1, Operand(prop->key()->AsLiteral()->handle()));
-
- Handle<Code> ic = is_strict_mode()
- ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
- : isolate()->builtins()->KeyedStoreIC_Initialize();
- __ Call(ic);
- // Value in v0 is ignored (declarations are statements).
+ case Slot::LOOKUP: {
+ __ li(a2, Operand(variable->name()));
+ // Declaration nodes are always introduced in one of two modes.
+ ASSERT(mode == Variable::VAR ||
+ mode == Variable::CONST ||
+ mode == Variable::LET);
+ PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
+ __ li(a1, Operand(Smi::FromInt(attr)));
+ // Push initial value, if any.
+ // Note: For variables we must not push an initial value (such as
+ // 'undefined') because we may have a (legal) redeclaration and we
+ // must not destroy the current value.
+ if (mode == Variable::CONST) {
+ __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
+ __ Push(cp, a2, a1, a0);
+ } else if (function != NULL) {
+ __ Push(cp, a2, a1);
+ // Push initial value for function declaration.
+ VisitForStackValue(function);
+ } else {
+ ASSERT(Smi::FromInt(0) == 0);
+ // No initial value!
+ __ mov(a0, zero_reg); // Operand(Smi::FromInt(0)));
+ __ Push(cp, a2, a1, a0);
+ }
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ break;
}
}
}
@@ -886,7 +853,7 @@
__ bind(&next_test);
__ Drop(1); // Switch value is no longer needed.
if (default_clause == NULL) {
- __ Branch(nested_statement.break_target());
+ __ Branch(nested_statement.break_label());
} else {
__ Branch(default_clause->body_target());
}
@@ -900,7 +867,7 @@
VisitStatements(clause->statements());
}
- __ bind(nested_statement.break_target());
+ __ bind(nested_statement.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
}
@@ -1026,7 +993,7 @@
// Load the current count to a0, load the length to a1.
__ lw(a0, MemOperand(sp, 0 * kPointerSize));
__ lw(a1, MemOperand(sp, 1 * kPointerSize));
- __ Branch(loop_statement.break_target(), hs, a0, Operand(a1));
+ __ Branch(loop_statement.break_label(), hs, a0, Operand(a1));
// Get the current entry of the array into register a3.
__ lw(a2, MemOperand(sp, 2 * kPointerSize));
@@ -1053,7 +1020,7 @@
__ push(a3); // Current entry.
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
__ mov(a3, result_register());
- __ Branch(loop_statement.continue_target(), eq, a3, Operand(zero_reg));
+ __ Branch(loop_statement.continue_label(), eq, a3, Operand(zero_reg));
// Update the 'each' property or variable from the possibly filtered
// entry in register a3.
@@ -1069,7 +1036,7 @@
// Generate code for the going to the next element by incrementing
// the index (smi) stored on top of the stack.
- __ bind(loop_statement.continue_target());
+ __ bind(loop_statement.continue_label());
__ pop(a0);
__ Addu(a0, a0, Operand(Smi::FromInt(1)));
__ push(a0);
@@ -1078,7 +1045,7 @@
__ Branch(&loop);
// Remove the pointers stored on the stack.
- __ bind(loop_statement.break_target());
+ __ bind(loop_statement.break_label());
__ Drop(5);
// Exit and decrement the loop depth.
@@ -1533,9 +1500,7 @@
// Update the write barrier for the array store with v0 as the scratch
// register.
- __ li(a2, Operand(offset));
- // TODO(PJ): double check this RecordWrite call.
- __ RecordWrite(a1, a2, result_register());
+ __ RecordWrite(a1, Operand(offset), a2, result_register());
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
}
@@ -2286,36 +2251,10 @@
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property.
- // For a synthetic property use keyed load IC followed by function call,
- // for a regular property use EmitKeyedCallWithIC.
- if (prop->is_synthetic()) {
- // Do not visit the object and key subexpressions (they are shared
- // by all occurrences of the same rewritten parameter).
- ASSERT(prop->obj()->AsVariableProxy() != NULL);
- ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
- Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
- MemOperand operand = EmitSlotSearch(slot, a1);
- __ lw(a1, operand);
-
- ASSERT(prop->key()->AsLiteral() != NULL);
- ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
- __ li(a0, Operand(prop->key()->AsLiteral()->handle()));
-
- // Record source code position for IC call.
- SetSourcePosition(prop->position());
-
- Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
- __ lw(a1, GlobalObjectOperand());
- __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
- __ Push(v0, a1); // Function, receiver.
- EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
- } else {
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(prop->obj());
}
+ EmitKeyedCallWithIC(expr, prop->key());
}
} else {
{ PreservePositionScope scope(masm()->positions_recorder());
@@ -2761,7 +2700,7 @@
// Objects with a non-function constructor have class 'Object'.
__ bind(&non_function_constructor);
- __ LoadRoot(v0, Heap::kfunction_class_symbolRootIndex);
+ __ LoadRoot(v0, Heap::kObject_symbolRootIndex);
__ jmp(&done);
// Non-JS objects have class null.
@@ -3602,39 +3541,6 @@
}
-void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) {
- ASSERT(args->length() == 1);
-
- // Load the function into v0.
- VisitForAccumulatorValue(args->at(0));
-
- // Prepare for the test.
- 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);
-
- // Test for strict mode function.
- __ lw(a1, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset));
- __ lw(a1, FieldMemOperand(a1, SharedFunctionInfo::kCompilerHintsOffset));
- __ And(at, a1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
- kSmiTagSize)));
- __ Branch(if_true, ne, at, Operand(zero_reg));
-
- // Test for native function.
- __ And(at, a1, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
- __ Branch(if_true, ne, at, Operand(zero_reg));
-
- // Not native or strict-mode function.
- __ Branch(if_false);
-
- PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- context()->Plug(if_true, if_false);
-}
-
-
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') {
@@ -3686,18 +3592,12 @@
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
if (prop != NULL) {
- if (prop->is_synthetic()) {
- // Result of deleting parameters is false, even when they rewrite
- // to accesses on the arguments object.
- context()->Plug(false);
- } else {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
- __ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
- __ push(a1);
- __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
- context()->Plug(v0);
- }
+ VisitForStackValue(prop->obj());
+ VisitForStackValue(prop->key());
+ __ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
+ __ push(a1);
+ __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+ context()->Plug(v0);
} else if (var != NULL) {
// Delete of an unqualified identifier is disallowed in strict mode
// but "delete this" is.
@@ -4052,6 +3952,10 @@
__ Branch(if_true, eq, v0, Operand(at));
__ LoadRoot(at, Heap::kFalseValueRootIndex);
Split(eq, v0, Operand(at), if_true, if_false, fall_through);
+ } else if (FLAG_harmony_typeof &&
+ check->Equals(isolate()->heap()->null_symbol())) {
+ __ LoadRoot(at, Heap::kNullValueRootIndex);
+ Split(eq, v0, Operand(at), if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at));
@@ -4069,8 +3973,10 @@
} else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(v0, if_false);
- __ LoadRoot(at, Heap::kNullValueRootIndex);
- __ Branch(if_true, eq, v0, Operand(at));
+ if (!FLAG_harmony_typeof) {
+ __ LoadRoot(at, Heap::kNullValueRootIndex);
+ __ Branch(if_true, eq, v0, Operand(at));
+ }
// Check for JS objects => true.
__ GetObjectType(v0, v0, a1);
__ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
@@ -4313,6 +4219,34 @@
#undef __
+#define __ ACCESS_MASM(masm())
+
+FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
+ int* stack_depth,
+ int* context_length) {
+ // The macros used here must preserve the result register.
+
+ // Because the handler block contains the context of the finally
+ // code, we can restore it directly from there for the finally code
+ // rather than iteratively unwinding contexts via their previous
+ // links.
+ __ Drop(*stack_depth); // Down to the handler block.
+ if (*context_length > 0) {
+ // Restore the context to its dedicated register and the stack.
+ __ lw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
+ __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ }
+ __ PopTryHandler();
+ __ Call(finally_entry_);
+
+ *stack_depth = 0;
+ *context_length = 0;
+ return previous_;
+}
+
+
+#undef __
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index da39962..85cb916 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -885,8 +885,8 @@
MemOperand unmapped_location =
GenerateUnmappedArgumentsLookup(masm, a0, a2, a3, &slow);
__ lw(a2, unmapped_location);
- __ Branch(&slow, eq, a2, Operand(a3));
__ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
+ __ Branch(&slow, eq, a2, Operand(a3));
__ mov(v0, a2);
__ Ret();
__ bind(&slow);
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 5e8d676..c7f727b 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -757,15 +757,20 @@
uint16_t pos,
uint16_t size) {
ASSERT(pos < 32);
- ASSERT(pos + size < 32);
+ ASSERT(pos + size < 33);
if (mips32r2) {
ext_(rt, rs, pos, size);
} else {
// Move rs to rt and shift it left then right to get the
// desired bitfield on the right side and zeroes on the left.
- sll(rt, rs, 32 - (pos + size));
- srl(rt, rt, 32 - size);
+ int shift_left = 32 - (pos + size);
+ sll(rt, rs, shift_left); // Acts as a move if shift_left == 0.
+
+ int shift_right = 32 - size;
+ if (shift_right > 0) {
+ srl(rt, rt, shift_right);
+ }
}
}
@@ -807,28 +812,32 @@
}
-void MacroAssembler::Cvt_d_uw(FPURegister fd, FPURegister fs) {
- // Move the data from fs to t4.
- mfc1(t4, fs);
- return Cvt_d_uw(fd, t4);
+void MacroAssembler::Cvt_d_uw(FPURegister fd,
+ FPURegister fs,
+ FPURegister scratch) {
+ // Move the data from fs to t8.
+ mfc1(t8, fs);
+ Cvt_d_uw(fd, t8, scratch);
}
-void MacroAssembler::Cvt_d_uw(FPURegister fd, Register rs) {
+void MacroAssembler::Cvt_d_uw(FPURegister fd,
+ Register rs,
+ FPURegister scratch) {
// Convert rs to a FP value in fd (and fd + 1).
// We do this by converting rs minus the MSB to avoid sign conversion,
- // then adding 2^31-1 and 1 to the result.
+ // then adding 2^31 to the result (if needed).
- ASSERT(!fd.is(f20));
+ ASSERT(!fd.is(scratch));
ASSERT(!rs.is(t9));
- ASSERT(!rs.is(t8));
+ ASSERT(!rs.is(at));
- // Save rs's MSB to t8.
- And(t8, rs, 0x80000000);
+ // Save rs's MSB to t9.
+ Ext(t9, rs, 31, 1);
// Remove rs's MSB.
- And(t9, rs, 0x7FFFFFFF);
- // Move t9 to fd.
- mtc1(t9, fd);
+ Ext(at, rs, 0, 31);
+ // Move the result to fd.
+ mtc1(at, fd);
// Convert fd to a real FP value.
cvt_d_w(fd, fd);
@@ -837,41 +846,39 @@
// If rs's MSB was 0, it's done.
// Otherwise we need to add that to the FP register.
- Branch(&conversion_done, eq, t8, Operand(zero_reg));
+ Branch(&conversion_done, eq, t9, Operand(zero_reg));
- // First load 2^31 - 1 into f20.
- Or(t9, zero_reg, 0x7FFFFFFF);
- mtc1(t9, f20);
+ // Load 2^31 into f20 as its float representation.
+ li(at, 0x41E00000);
+ mtc1(at, FPURegister::from_code(scratch.code() + 1));
+ mtc1(zero_reg, scratch);
+ // Add it to fd.
+ add_d(fd, fd, scratch);
- // Convert it to FP and add it to fd.
- cvt_d_w(f20, f20);
- add_d(fd, fd, f20);
- // Now add 1.
- Or(t9, zero_reg, 1);
- mtc1(t9, f20);
-
- cvt_d_w(f20, f20);
- add_d(fd, fd, f20);
bind(&conversion_done);
}
-void MacroAssembler::Trunc_uw_d(FPURegister fd, FPURegister fs) {
- Trunc_uw_d(fs, t4);
- mtc1(t4, fd);
+void MacroAssembler::Trunc_uw_d(FPURegister fd,
+ FPURegister fs,
+ FPURegister scratch) {
+ Trunc_uw_d(fs, t8, scratch);
+ mtc1(t8, fd);
}
-void MacroAssembler::Trunc_uw_d(FPURegister fd, Register rs) {
- ASSERT(!fd.is(f22));
- ASSERT(!rs.is(t8));
+void MacroAssembler::Trunc_uw_d(FPURegister fd,
+ Register rs,
+ FPURegister scratch) {
+ ASSERT(!fd.is(scratch));
+ ASSERT(!rs.is(at));
- // Load 2^31 into f22.
- Or(t8, zero_reg, 0x80000000);
- Cvt_d_uw(f22, t8);
-
- // Test if f22 > fd.
- c(OLT, D, fd, f22);
+ // Load 2^31 into scratch as its float representation.
+ li(at, 0x41E00000);
+ mtc1(at, FPURegister::from_code(scratch.code() + 1));
+ mtc1(zero_reg, scratch);
+ // Test if scratch > fd.
+ c(OLT, D, fd, scratch);
Label simple_convert;
// If fd < 2^31 we can convert it normally.
@@ -879,18 +886,17 @@
// First we subtract 2^31 from fd, then trunc it to rs
// and add 2^31 to rs.
-
- sub_d(f22, fd, f22);
- trunc_w_d(f22, f22);
- mfc1(rs, f22);
- or_(rs, rs, t8);
+ sub_d(scratch, fd, scratch);
+ trunc_w_d(scratch, scratch);
+ mfc1(rs, scratch);
+ Or(rs, rs, 1 << 31);
Label done;
Branch(&done);
// Simple conversion.
bind(&simple_convert);
- trunc_w_d(f22, fd);
- mfc1(rs, f22);
+ trunc_w_d(scratch, fd);
+ mfc1(rs, scratch);
bind(&done);
}
@@ -1551,12 +1557,14 @@
b(offset);
break;
case eq:
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
offset = shifted_branch_offset(L, false);
beq(rs, r2, offset);
break;
case ne:
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
offset = shifted_branch_offset(L, false);
@@ -1568,6 +1576,7 @@
offset = shifted_branch_offset(L, false);
bgtz(rs, offset);
} else {
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
slt(scratch, r2, rs);
@@ -1584,6 +1593,7 @@
offset = shifted_branch_offset(L, false);
beq(scratch, zero_reg, offset);
} else {
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
slt(scratch, rs, r2);
@@ -1600,6 +1610,7 @@
offset = shifted_branch_offset(L, false);
bne(scratch, zero_reg, offset);
} else {
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
slt(scratch, rs, r2);
@@ -1612,6 +1623,7 @@
offset = shifted_branch_offset(L, false);
blez(rs, offset);
} else {
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
slt(scratch, r2, rs);
@@ -1625,6 +1637,7 @@
offset = shifted_branch_offset(L, false);
bgtz(rs, offset);
} else {
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
sltu(scratch, r2, rs);
@@ -1641,6 +1654,7 @@
offset = shifted_branch_offset(L, false);
beq(scratch, zero_reg, offset);
} else {
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
sltu(scratch, rs, r2);
@@ -1657,6 +1671,7 @@
offset = shifted_branch_offset(L, false);
bne(scratch, zero_reg, offset);
} else {
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
sltu(scratch, rs, r2);
@@ -1669,6 +1684,7 @@
offset = shifted_branch_offset(L, false);
b(offset);
} else {
+ ASSERT(!scratch.is(rs));
r2 = scratch;
li(r2, rt);
sltu(scratch, r2, rs);
@@ -2244,7 +2260,13 @@
void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) {
// Adjust this code if not the case.
- ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
+
// The return address is passed in register ra.
if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) {
@@ -2252,19 +2274,16 @@
} else {
li(t0, Operand(StackHandler::TRY_FINALLY));
}
- ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
- && StackHandlerConstants::kFPOffset == 2 * kPointerSize
- && StackHandlerConstants::kPCOffset == 3 * kPointerSize
- && StackHandlerConstants::kNextOffset == 0 * kPointerSize);
// Save the current handler as the next handler.
li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
lw(t1, MemOperand(t2));
addiu(sp, sp, -StackHandlerConstants::kSize);
- sw(ra, MemOperand(sp, 12));
- sw(fp, MemOperand(sp, 8));
- sw(t0, MemOperand(sp, 4));
- sw(t1, MemOperand(sp, 0));
+ sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset));
+ sw(fp, MemOperand(sp, StackHandlerConstants::kFPOffset));
+ sw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
+ sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset));
+ sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset));
// Link this handler as the new current one.
sw(sp, MemOperand(t2));
@@ -2272,11 +2291,6 @@
} else {
// Must preserve a0-a3, and s0 (argv).
ASSERT(try_location == IN_JS_ENTRY);
- ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
- && StackHandlerConstants::kFPOffset == 2 * kPointerSize
- && StackHandlerConstants::kPCOffset == 3 * kPointerSize
- && StackHandlerConstants::kNextOffset == 0 * kPointerSize);
-
// The frame pointer does not point to a JS frame so we save NULL
// for fp. We expect the code throwing an exception to check fp
// before dereferencing it to restore the context.
@@ -2286,11 +2300,14 @@
li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
lw(t1, MemOperand(t2));
+ ASSERT(Smi::FromInt(0) == 0); // Used for no context.
+
addiu(sp, sp, -StackHandlerConstants::kSize);
- sw(ra, MemOperand(sp, 12));
- sw(zero_reg, MemOperand(sp, 8));
- sw(t0, MemOperand(sp, 4));
- sw(t1, MemOperand(sp, 0));
+ sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset));
+ sw(zero_reg, MemOperand(sp, StackHandlerConstants::kFPOffset));
+ sw(zero_reg, MemOperand(sp, StackHandlerConstants::kContextOffset));
+ sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset));
+ sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset));
// Link this handler as the new current one.
sw(sp, MemOperand(t2));
@@ -2299,7 +2316,7 @@
void MacroAssembler::PopTryHandler() {
- ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a1);
Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
@@ -2312,28 +2329,31 @@
Move(v0, value);
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// Drop the sp to the top of the handler.
li(a3, Operand(ExternalReference(Isolate::k_handler_address,
- isolate())));
+ isolate())));
lw(sp, MemOperand(a3));
- // Restore the next handler and frame pointer, discard handler state.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+ // Restore the next handler.
pop(a2);
sw(a2, MemOperand(a3));
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
- MultiPop(a3.bit() | fp.bit());
- // Before returning we restore the context from the frame pointer if
- // not NULL. The frame pointer is NULL in the exception handler of a
- // JS entry frame.
- // Set cp to NULL if fp is NULL.
+ // Restore context and frame pointer, discard state (a3).
+ MultiPop(a3.bit() | cp.bit() | fp.bit());
+
+ // If the handler is a JS frame, restore the context to the frame.
+ // (a3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any
+ // of them.
Label done;
- Branch(USE_DELAY_SLOT, &done, eq, fp, Operand(zero_reg));
- mov(cp, zero_reg); // In branch delay slot.
- lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ Branch(&done, eq, fp, Operand(zero_reg));
+ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
bind(&done);
#ifdef DEBUG
@@ -2355,7 +2375,6 @@
}
#endif
- STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(t9); // 2 instructions: lw, add sp.
Jump(t9); // 2 instructions: jr, nop (in delay slot).
@@ -2370,7 +2389,12 @@
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// v0 is expected to hold the exception.
Move(v0, value);
@@ -2393,7 +2417,6 @@
bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a2);
sw(a2, MemOperand(a3));
@@ -2415,20 +2438,12 @@
// Stack layout at this point. See also StackHandlerConstants.
// sp -> state (ENTRY)
+ // cp
// fp
// ra
- // Discard handler state (a2 is not used) and restore frame pointer.
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
- MultiPop(a2.bit() | fp.bit()); // a2: discarded state.
- // Before returning we restore the context from the frame pointer if
- // not NULL. The frame pointer is NULL in the exception handler of a
- // JS entry frame.
- Label cp_null;
- Branch(USE_DELAY_SLOT, &cp_null, eq, fp, Operand(zero_reg));
- mov(cp, zero_reg); // In the branch delay slot.
- lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- bind(&cp_null);
+ // Restore context and frame pointer, discard state (r2).
+ MultiPop(a2.bit() | cp.bit() | fp.bit());
#ifdef DEBUG
// When emitting debug_code, set ra as return address for the jump.
@@ -2448,7 +2463,6 @@
addiu(ra, ra, kOffsetRaBytes);
}
#endif
- STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(t9); // 2 instructions: lw, add sp.
Jump(t9); // 2 instructions: jr, nop (in delay slot).
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 4994516..0fcf6f1 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -524,12 +524,12 @@
void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
// Convert unsigned word to double.
- void Cvt_d_uw(FPURegister fd, FPURegister fs);
- void Cvt_d_uw(FPURegister fd, Register rs);
+ void Cvt_d_uw(FPURegister fd, FPURegister fs, FPURegister scratch);
+ void Cvt_d_uw(FPURegister fd, Register rs, FPURegister scratch);
// Convert double to unsigned word.
- void Trunc_uw_d(FPURegister fd, FPURegister fs);
- void Trunc_uw_d(FPURegister fd, Register rs);
+ void Trunc_uw_d(FPURegister fd, FPURegister fs, FPURegister scratch);
+ void Trunc_uw_d(FPURegister fd, Register rs, FPURegister scratch);
// Convert the HeapNumber pointed to by source to a 32bits signed integer
// dest. If the HeapNumber does not fit into a 32bits signed integer branch
diff --git a/src/mips/regexp-macro-assembler-mips.cc b/src/mips/regexp-macro-assembler-mips.cc
index 9935ef9..63e836f 100644
--- a/src/mips/regexp-macro-assembler-mips.cc
+++ b/src/mips/regexp-macro-assembler-mips.cc
@@ -1036,12 +1036,12 @@
}
// Prepare for possible GC.
- HandleScope handles;
+ HandleScope handles(isolate);
Handle<Code> code_handle(re_code);
Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
// Current string.
- bool is_ascii = subject->IsAsciiRepresentation();
+ bool is_ascii = subject->IsAsciiRepresentationUnderneath();
ASSERT(re_code->instruction_start() <= *return_address);
ASSERT(*return_address <=
@@ -1050,7 +1050,7 @@
MaybeObject* result = Execution::HandleStackGuardInterrupt();
if (*code_handle != re_code) { // Return address no longer valid.
- int delta = *code_handle - re_code;
+ int delta = code_handle->address() - re_code->address();
// Overwrite the return address on the stack.
*return_address += delta;
}
@@ -1059,8 +1059,20 @@
return EXCEPTION;
}
+ Handle<String> subject_tmp = subject;
+ int slice_offset = 0;
+
+ // Extract the underlying string and the slice offset.
+ if (StringShape(*subject_tmp).IsCons()) {
+ subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
+ } else if (StringShape(*subject_tmp).IsSliced()) {
+ SlicedString* slice = SlicedString::cast(*subject_tmp);
+ subject_tmp = Handle<String>(slice->parent());
+ slice_offset = slice->offset();
+ }
+
// String might have changed.
- if (subject->IsAsciiRepresentation() != is_ascii) {
+ if (subject_tmp->IsAsciiRepresentation() != is_ascii) {
// If we changed between an ASCII and an UC16 string, the specialized
// code cannot be used, and we need to restart regexp matching from
// scratch (including, potentially, compiling a new version of the code).
@@ -1071,8 +1083,8 @@
// be a sequential or external string with the same content.
// Update the start and end pointers in the stack frame to the current
// location (whether it has actually moved or not).
- ASSERT(StringShape(*subject).IsSequential() ||
- StringShape(*subject).IsExternal());
+ ASSERT(StringShape(*subject_tmp).IsSequential() ||
+ StringShape(*subject_tmp).IsExternal());
// The original start address of the characters to match.
const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
@@ -1080,13 +1092,14 @@
// Find the current start address of the same character at the current string
// position.
int start_index = frame_entry<int>(re_frame, kStartIndex);
- const byte* new_address = StringCharacterPosition(*subject, start_index);
+ const byte* new_address = StringCharacterPosition(*subject_tmp,
+ start_index + slice_offset);
if (start_address != new_address) {
// If there is a difference, update the object pointer and start and end
// addresses in the RegExp stack frame to match the new value.
const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
- int byte_length = end_address - start_address;
+ int byte_length = static_cast<int>(end_address - start_address);
frame_entry<const String*>(re_frame, kInputString) = *subject;
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 30e12e7..3b38695 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -1409,20 +1409,11 @@
int32_t arg1 = get_register(a1);
int32_t arg2 = get_register(a2);
int32_t arg3 = get_register(a3);
- int32_t arg4 = 0;
- int32_t arg5 = 0;
- // Need to check if sp is valid before assigning arg4, arg5.
- // This is a fix for cctest test-api/CatchStackOverflow which causes
- // the stack to overflow. For some reason arm doesn't need this
- // stack check here.
int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
- int32_t* stack = reinterpret_cast<int32_t*>(stack_);
- if (stack_pointer >= stack && stack_pointer < stack + stack_size_ - 5) {
- // Args 4 and 5 are on the stack after the reserved space for args 0..3.
- arg4 = stack_pointer[4];
- arg5 = stack_pointer[5];
- }
+ // Args 4 and 5 are on the stack after the reserved space for args 0..3.
+ int32_t arg4 = stack_pointer[4];
+ int32_t arg5 = stack_pointer[5];
bool fp_call =
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index f1ffe9b..c17a658 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -3494,7 +3494,7 @@
__ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
__ sra(t2, key, kSmiTagSize);
// Unsigned comparison catches both negative and too-large values.
- __ Branch(&miss_force_generic, Uless, t1, Operand(t2));
+ __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
__ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
// a3: base pointer of external storage
@@ -3638,7 +3638,7 @@
// __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
// __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
- __ Cvt_d_uw(f0, value);
+ __ Cvt_d_uw(f0, value, f22);
__ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
@@ -3822,16 +3822,16 @@
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check that the key is a smi.
+ // Check that the key is a smi.
__ JumpIfNotSmi(key, &miss_force_generic);
+ __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
+
// Check that the index is in range.
__ SmiUntag(t0, key);
__ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
- __ Branch(&miss_force_generic, Ugreater_equal, t0, Operand(t1));
+ __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
@@ -4428,7 +4428,8 @@
__ sw(mantissa_reg, FieldMemOperand(scratch, FixedDoubleArray::kHeaderSize));
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
__ sw(exponent_reg, FieldMemOperand(scratch, offset));
- __ Ret();
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, value_reg); // In delay slot.
__ bind(&maybe_nan);
// Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
@@ -4459,11 +4460,18 @@
} else {
destination = FloatingPointHelper::kCoreRegisters;
}
- __ SmiUntag(value_reg, value_reg);
+
+ Register untagged_value = receiver_reg;
+ __ SmiUntag(untagged_value, value_reg);
FloatingPointHelper::ConvertIntToDouble(
- masm, value_reg, destination,
- f0, mantissa_reg, exponent_reg, // These are: double_dst, dst1, dst2.
- scratch4, f2); // These are: scratch2, single_scratch.
+ masm,
+ untagged_value,
+ destination,
+ f0,
+ mantissa_reg,
+ exponent_reg,
+ scratch4,
+ f2);
if (destination == FloatingPointHelper::kFPURegisters) {
CpuFeatures::Scope scope(FPU);
__ sdc1(f0, MemOperand(scratch, 0));
@@ -4471,7 +4479,8 @@
__ sw(mantissa_reg, MemOperand(scratch, 0));
__ sw(exponent_reg, MemOperand(scratch, Register::kSizeInBytes));
}
- __ Ret();
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, value_reg); // In delay slot.
// Handle store cache miss, replacing the ic with the generic stub.
__ bind(&miss_force_generic);