}
-void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
- Register index,
- Register value,
- uint32_t encoding_mask) {
- __ SmiTst(index);
- __ Check(eq, kNonSmiIndex);
- __ SmiTst(value);
- __ Check(eq, kNonSmiValue);
-
- __ ldr(ip, FieldMemOperand(string, String::kLengthOffset));
- __ cmp(index, ip);
- __ Check(lt, kIndexIsTooLarge);
-
- __ cmp(index, Operand(Smi::FromInt(0)));
- __ Check(ge, kIndexIsNegative);
-
- __ ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset));
- __ ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
-
- __ and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
- __ cmp(ip, Operand(encoding_mask));
- __ Check(eq, kUnexpectedStringType);
-}
-
-
void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
__ Pop(index, value);
if (FLAG_debug_code) {
+ __ SmiTst(value);
+ __ ThrowIf(ne, kNonSmiValue);
+ __ SmiTst(index);
+ __ ThrowIf(ne, kNonSmiIndex);
+ __ SmiUntag(index, index);
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
- EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ __ SmiTag(index, index);
}
__ SmiUntag(value, value);
__ Pop(index, value);
if (FLAG_debug_code) {
+ __ SmiTst(value);
+ __ ThrowIf(ne, kNonSmiValue);
+ __ SmiTst(index);
+ __ ThrowIf(ne, kNonSmiIndex);
+ __ SmiUntag(index, index);
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ __ SmiTag(index, index);
}
__ SmiUntag(value, value);
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
- LOperand* string = UseRegister(instr->string());
- LOperand* index = UseRegisterOrConstant(instr->index());
- LOperand* value = UseRegister(instr->value());
- return new(zone()) LSeqStringSetChar(string, index, value);
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = FLAG_debug_code
+ ? UseRegisterAtStart(instr->index())
+ : UseRegisterOrConstantAtStart(instr->index());
+ LOperand* value = UseRegisterAtStart(instr->value());
+ LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
+ return new(zone()) LSeqStringSetChar(context, string, index, value);
}
};
-class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
+class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> {
public:
- LSeqStringSetChar(LOperand* string,
+ LSeqStringSetChar(LOperand* context,
+ LOperand* string,
LOperand* index,
LOperand* value) {
- inputs_[0] = string;
- inputs_[1] = index;
- inputs_[2] = value;
+ inputs_[0] = context;
+ inputs_[1] = string;
+ inputs_[2] = index;
+ inputs_[3] = value;
}
- LOperand* string() { return inputs_[0]; }
- LOperand* index() { return inputs_[1]; }
- LOperand* value() { return inputs_[2]; }
+ LOperand* string() { return inputs_[1]; }
+ LOperand* index() { return inputs_[2]; }
+ LOperand* value() { return inputs_[3]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
Register value = ToRegister(instr->value());
if (FLAG_debug_code) {
- Register scratch = scratch0();
- __ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
- __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
-
- __ and_(scratch, scratch,
- Operand(kStringRepresentationMask | kStringEncodingMask));
+ Register index = ToRegister(instr->index());
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- __ cmp(scratch, Operand(encoding == String::ONE_BYTE_ENCODING
- ? one_byte_seq_type : two_byte_seq_type));
- __ Check(eq, kUnexpectedStringType);
+ int encoding_mask =
+ instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type;
+ __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
}
MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
}
+void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask) {
+ Label is_object;
+ SmiTst(string);
+ ThrowIf(eq, kNonObject);
+
+ ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset));
+ ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
+
+ and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
+ cmp(ip, Operand(encoding_mask));
+ ThrowIf(ne, kUnexpectedStringType);
+
+ // The index is assumed to be untagged coming in, tag it to compare with the
+ // string length without using a temp register, it is restored at the end of
+ // this function.
+ Label index_tag_ok, index_tag_bad;
+ TrySmiTag(index, index, &index_tag_bad);
+ b(&index_tag_ok);
+ bind(&index_tag_bad);
+ Throw(kIndexIsTooLarge);
+ bind(&index_tag_ok);
+
+ ldr(ip, FieldMemOperand(string, String::kLengthOffset));
+ cmp(index, ip);
+ ThrowIf(ge, kIndexIsTooLarge);
+
+ cmp(index, Operand(Smi::FromInt(0)));
+ ThrowIf(lt, kIndexIsNegative);
+
+ SmiUntag(index, index);
+}
+
+
void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
int num_double_arguments,
Register scratch) {
}
+void MacroAssembler::Throw(BailoutReason reason) {
+ Label throw_start;
+ bind(&throw_start);
+#ifdef DEBUG
+ const char* msg = GetBailoutReason(reason);
+ if (msg != NULL) {
+ RecordComment("Throw message: ");
+ RecordComment(msg);
+ }
+#endif
+
+ mov(r0, Operand(Smi::FromInt(reason)));
+ push(r0);
+ // Disable stub call restrictions to always allow calls to throw.
+ if (!has_frame_) {
+ // We don't actually want to generate a pile of code for this, so just
+ // claim there is a stack frame, without generating one.
+ FrameScope scope(this, StackFrame::NONE);
+ CallRuntime(Runtime::kThrowMessage, 1);
+ } else {
+ CallRuntime(Runtime::kThrowMessage, 1);
+ }
+ // will not return here
+ if (is_const_pool_blocked()) {
+ // If the calling code cares throw the exact number of
+ // instructions generated, we insert padding here to keep the size
+ // of the ThrowMessage macro constant.
+ static const int kExpectedThrowMessageInstructions = 10;
+ int throw_instructions = InstructionsGeneratedSince(&throw_start);
+ ASSERT(throw_instructions <= kExpectedThrowMessageInstructions);
+ while (throw_instructions++ < kExpectedThrowMessageInstructions) {
+ nop();
+ }
+ }
+}
+
+
+void MacroAssembler::ThrowIf(Condition cc, BailoutReason reason) {
+ Label L;
+ b(NegateCondition(cc), &L);
+ Throw(reason);
+ // will not return here
+ bind(&L);
+}
+
+
void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors) {
ldr(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
// handler chain.
void ThrowUncatchable(Register value);
+ // Throw a message string as an exception.
+ void Throw(BailoutReason reason);
+
+ // Throw a message string as an exception if a condition is not true.
+ void ThrowIf(Condition cc, BailoutReason reason);
+
// ---------------------------------------------------------------------------
// Inline caching support
void JumpIfNotUniqueName(Register reg, Label* not_unique_name);
+ void EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask);
+
// ---------------------------------------------------------------------------
// Patching helpers.
INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
#undef EMIT_INLINE_RUNTIME_CALL
- void EmitSeqStringSetCharCheck(Register string,
- Register index,
- Register value,
- uint32_t encoding_mask);
-
// Platform-specific code for resuming generators.
void EmitGeneratorResume(Expression *generator,
Expression *value,
};
-class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<3> {
+class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<4> {
public:
- DECLARE_INSTRUCTION_FACTORY_P4(HSeqStringSetChar, String::Encoding,
- HValue*, HValue*, HValue*);
+ DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
+ HSeqStringSetChar, String::Encoding,
+ HValue*, HValue*, HValue*);
String::Encoding encoding() { return encoding_; }
- HValue* string() { return OperandAt(0); }
- HValue* index() { return OperandAt(1); }
- HValue* value() { return OperandAt(2); }
+ HValue* context() { return OperandAt(0); }
+ HValue* string() { return OperandAt(1); }
+ HValue* index() { return OperandAt(2); }
+ HValue* value() { return OperandAt(3); }
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
- return (index == 0) ? Representation::Tagged()
+ return (index <= 1) ? Representation::Tagged()
: Representation::Integer32();
}
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
private:
- HSeqStringSetChar(String::Encoding encoding,
+ HSeqStringSetChar(HValue* context,
+ String::Encoding encoding,
HValue* string,
HValue* index,
HValue* value) : encoding_(encoding) {
- SetOperandAt(0, string);
- SetOperandAt(1, index);
- SetOperandAt(2, value);
+ SetOperandAt(0, context);
+ SetOperandAt(1, string);
+ SetOperandAt(2, index);
+ SetOperandAt(3, value);
set_representation(Representation::Tagged());
SetGVNFlag(kChangesStringChars);
}
// We can safely skip the write barrier for storing map here.
AddStoreMapConstantNoWriteBarrier(string, map);
+ // Length must be stored into the string before we copy characters to
+ // make debug verification code happy.
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+ length);
+
// Copy bytes from the left string.
BuildCopySeqStringChars(
left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
// We can safely skip the write barrier for storing map here.
AddStoreMapConstantNoWriteBarrier(string, map);
+ // Length must be stored into the string before we copy characters to
+ // make debug verification code happy.
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+ length);
+
// Copy bytes from the left string.
BuildCopySeqStringChars(
left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
HValue* string = Pop();
Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
Add<HConstant>(String::kEmptyHashField));
- Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
- length);
Push(string);
}
if_sameencodingandsequential.JoinContinuation(&handled);
HValue* value = Pop();
HValue* index = Pop();
HValue* string = Pop();
- HSeqStringSetChar* result = New<HSeqStringSetChar>(
- String::ONE_BYTE_ENCODING, string, index, value);
- return ast_context()->ReturnInstruction(result, call->id());
+ Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string,
+ index, value);
+ Add<HSimulate>(call->id(), FIXED_SIMULATE);
+ return ast_context()->ReturnValue(graph()->GetConstantUndefined());
}
HValue* value = Pop();
HValue* index = Pop();
HValue* string = Pop();
- HSeqStringSetChar* result = New<HSeqStringSetChar>(
- String::TWO_BYTE_ENCODING, string, index, value);
- return ast_context()->ReturnInstruction(result, call->id());
+ Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string,
+ index, value);
+ Add<HSimulate>(call->id(), FIXED_SIMULATE);
+ return ast_context()->ReturnValue(graph()->GetConstantUndefined());
}
}
-void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
- Register index,
- Register value,
- uint32_t encoding_mask) {
- __ test(index, Immediate(kSmiTagMask));
- __ Check(zero, kNonSmiIndex);
- __ test(value, Immediate(kSmiTagMask));
- __ Check(zero, kNonSmiValue);
-
- __ cmp(index, FieldOperand(string, String::kLengthOffset));
- __ Check(less, kIndexIsTooLarge);
-
- __ cmp(index, Immediate(Smi::FromInt(0)));
- __ Check(greater_equal, kIndexIsNegative);
-
- __ push(value);
- __ mov(value, FieldOperand(string, HeapObject::kMapOffset));
- __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
-
- __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
- __ cmp(value, Immediate(encoding_mask));
- __ Check(equal, kUnexpectedStringType);
- __ pop(value);
-}
-
-
void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
__ pop(index);
if (FLAG_debug_code) {
- static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
- EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ __ test(value, Immediate(kSmiTagMask));
+ __ ThrowIf(not_zero, kNonSmiValue);
+ __ test(index, Immediate(kSmiTagMask));
+ __ ThrowIf(not_zero, kNonSmiValue);
}
__ SmiUntag(value);
__ SmiUntag(index);
+
+ if (FLAG_debug_code) {
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ }
+
__ mov_b(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
value);
context()->Plug(string);
__ pop(index);
if (FLAG_debug_code) {
+ __ test(value, Immediate(kSmiTagMask));
+ __ ThrowIf(not_zero, kNonSmiValue);
+ __ test(index, Immediate(kSmiTagMask));
+ __ ThrowIf(not_zero, kNonSmiValue);
+ __ SmiUntag(index);
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ __ SmiTag(index);
}
__ SmiUntag(value);
Register string = ToRegister(instr->string());
if (FLAG_debug_code) {
- __ push(string);
- __ mov(string, FieldOperand(string, HeapObject::kMapOffset));
- __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset));
-
- __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ Register value = ToRegister(instr->value());
+ Register index = ToRegister(instr->index());
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING
- ? one_byte_seq_type : two_byte_seq_type));
- __ Check(equal, kUnexpectedStringType);
- __ pop(string);
+ int encoding_mask =
+ instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type;
+ __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
}
Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
}
+LOperand* LChunkBuilder::GetSeqStringSetCharOperand(HSeqStringSetChar* instr) {
+ if (instr->encoding() == String::ONE_BYTE_ENCODING) {
+ if (FLAG_debug_code) {
+ return UseFixed(instr->value(), eax);
+ } else {
+ return UseFixedOrConstant(instr->value(), eax);
+ }
+ } else {
+ if (FLAG_debug_code) {
+ return UseRegisterAtStart(instr->value());
+ } else {
+ return UseRegisterOrConstantAtStart(instr->value());
+ }
+ }
+}
+
+
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
LOperand* string = UseRegisterAtStart(instr->string());
- LOperand* index = UseRegisterOrConstantAtStart(instr->index());
- LOperand* value = (instr->encoding() == String::ONE_BYTE_ENCODING)
- ? UseFixedOrConstant(instr->value(), eax)
- : UseRegisterOrConstantAtStart(instr->value());
- return new(zone()) LSeqStringSetChar(string, index, value);
+ LOperand* index = FLAG_debug_code
+ ? UseRegisterAtStart(instr->index())
+ : UseRegisterOrConstantAtStart(instr->index());
+ LOperand* value = GetSeqStringSetCharOperand(instr);
+ LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), esi) : NULL;
+ LInstruction* result = new(zone()) LSeqStringSetChar(context, string,
+ index, value);
+ if (FLAG_debug_code) {
+ result = MarkAsCall(result, instr);
+ }
+ return result;
}
};
-class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
+class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> {
public:
- LSeqStringSetChar(LOperand* string,
+ LSeqStringSetChar(LOperand* context,
+ LOperand* string,
LOperand* index,
LOperand* value) {
- inputs_[0] = string;
- inputs_[1] = index;
- inputs_[2] = value;
+ inputs_[0] = context;
+ inputs_[1] = string;
+ inputs_[2] = index;
+ inputs_[3] = value;
}
- LOperand* string() { return inputs_[0]; }
- LOperand* index() { return inputs_[1]; }
- LOperand* value() { return inputs_[2]; }
+ LOperand* string() { return inputs_[1]; }
+ LOperand* index() { return inputs_[2]; }
+ LOperand* value() { return inputs_[3]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
+ LOperand* GetSeqStringSetCharOperand(HSeqStringSetChar* instr);
+
// Marks a call for the register allocator. Assigns a pointer map to
// support GC and lazy deoptimization. Assigns an environment to support
// eager deoptimization if CAN_DEOPTIMIZE_EAGERLY.
}
+void MacroAssembler::Throw(BailoutReason reason) {
+#ifdef DEBUG
+ const char* msg = GetBailoutReason(reason);
+ if (msg != NULL) {
+ RecordComment("Throw message: ");
+ RecordComment(msg);
+ }
+#endif
+
+ push(eax);
+ push(Immediate(Smi::FromInt(reason)));
+ // Disable stub call restrictions to always allow calls to throw.
+ if (!has_frame_) {
+ // We don't actually want to generate a pile of code for this, so just
+ // claim there is a stack frame, without generating one.
+ FrameScope scope(this, StackFrame::NONE);
+ CallRuntime(Runtime::kThrowMessage, 1);
+ } else {
+ CallRuntime(Runtime::kThrowMessage, 1);
+ }
+ // will not return here
+ int3();
+}
+
+
+void MacroAssembler::ThrowIf(Condition cc, BailoutReason reason) {
+ Label L;
+ j(NegateCondition(cc), &L);
+ Throw(reason);
+ // will not return here
+ bind(&L);
+}
+
+
void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors) {
mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
}
+void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask) {
+ Label is_object;
+ JumpIfNotSmi(string, &is_object, Label::kNear);
+ Throw(kNonObject);
+ bind(&is_object);
+
+ push(value);
+ mov(value, FieldOperand(string, HeapObject::kMapOffset));
+ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
+
+ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ cmp(value, Immediate(encoding_mask));
+ pop(value);
+ ThrowIf(not_equal, kUnexpectedStringType);
+
+ // The index is assumed to be untagged coming in, tag it to compare with the
+ // string length without using a temp register, it is restored at the end of
+ // this function.
+ SmiTag(index);
+ // Can't use overflow here directly, compiler can't seem to disambiguate.
+ ThrowIf(NegateCondition(no_overflow), kIndexIsTooLarge);
+
+ cmp(index, FieldOperand(string, String::kLengthOffset));
+ ThrowIf(greater_equal, kIndexIsTooLarge);
+
+ cmp(index, Immediate(Smi::FromInt(0)));
+ ThrowIf(less, kIndexIsNegative);
+
+ // Restore the index
+ SmiUntag(index);
+}
+
+
void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
int frame_alignment = OS::ActivationFrameAlignment();
if (frame_alignment != 0) {
// Throw past all JS frames to the top JS entry frame.
void ThrowUncatchable(Register value);
+ // Throw a message string as an exception.
+ void Throw(BailoutReason reason);
+
+ // Throw a message string as an exception if a condition is not true.
+ void ThrowIf(Condition cc, BailoutReason reason);
+
// ---------------------------------------------------------------------------
// Inline caching support
void JumpIfNotUniqueName(Operand operand, Label* not_unique_name,
Label::Distance distance = Label::kFar);
+ void EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask);
+
static int SafepointRegisterStackIndex(Register reg) {
return SafepointRegisterStackIndex(reg.code());
}
V(kNonSmiIndex, "Non-smi index") \
V(kNonSmiKeyInArrayLiteral, "Non-smi key in array literal") \
V(kNonSmiValue, "Non-smi value") \
+ V(kNonObject, "Non-object value") \
V(kNotEnoughVirtualRegistersForValues, \
"not enough virtual registers for values") \
V(kNotEnoughSpillSlotsForOsr, \
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowMessage) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_SMI_ARG_CHECKED(message_id, 0);
+ const char* message = GetBailoutReason(
+ static_cast<BailoutReason>(message_id));
+ Handle<Name> message_handle =
+ isolate->factory()->NewStringFromAscii(CStrVector(message));
+ return isolate->Throw(*message_handle);
+}
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
SealHandleScope shs(isolate);
F(ReThrow, 1, 1) \
F(ThrowReferenceError, 1, 1) \
F(ThrowNotDateError, 0, 1) \
+ F(ThrowMessage, 1, 1) \
F(StackGuard, 0, 1) \
F(Interrupt, 0, 1) \
F(PromoteScheduledException, 0, 1) \
}
-void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
- Register index,
- Register value,
- uint32_t encoding_mask) {
- __ Check(masm()->CheckSmi(index), kNonSmiIndex);
- __ Check(masm()->CheckSmi(value), kNonSmiValue);
-
- __ SmiCompare(index, FieldOperand(string, String::kLengthOffset));
- __ Check(less, kIndexIsTooLarge);
-
- __ SmiCompare(index, Smi::FromInt(0));
- __ Check(greater_equal, kIndexIsNegative);
-
- __ push(value);
- __ movq(value, FieldOperand(string, HeapObject::kMapOffset));
- __ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
-
- __ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
- __ cmpq(value, Immediate(encoding_mask));
- __ Check(equal, kUnexpectedStringType);
- __ pop(value);
-}
-
-
void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
__ pop(index);
if (FLAG_debug_code) {
- static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
- EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ __ ThrowIf(NegateCondition(__ CheckSmi(value)), kNonSmiValue);
+ __ ThrowIf(NegateCondition(__ CheckSmi(index)), kNonSmiValue);
}
__ SmiToInteger32(value, value);
__ SmiToInteger32(index, index);
+
+ if (FLAG_debug_code) {
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ }
+
__ movb(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
value);
context()->Plug(string);
__ pop(index);
if (FLAG_debug_code) {
- static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ __ ThrowIf(NegateCondition(__ CheckSmi(value)), kNonSmiValue);
+ __ ThrowIf(NegateCondition(__ CheckSmi(index)), kNonSmiValue);
}
__ SmiToInteger32(value, value);
__ SmiToInteger32(index, index);
+
+ if (FLAG_debug_code) {
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ }
+
__ movw(FieldOperand(string, index, times_2, SeqTwoByteString::kHeaderSize),
value);
context()->Plug(rax);
Register string = ToRegister(instr->string());
if (FLAG_debug_code) {
- __ push(string);
- __ movq(string, FieldOperand(string, HeapObject::kMapOffset));
- __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset));
-
- __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ Register value = ToRegister(instr->value());
+ Register index = ToRegister(instr->index());
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING
- ? one_byte_seq_type : two_byte_seq_type));
- __ Check(equal, kUnexpectedStringType);
- __ pop(string);
+ int encoding_mask =
+ instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type;
+ __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
}
Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
LOperand* string = UseRegisterAtStart(instr->string());
- LOperand* index = UseRegisterOrConstantAtStart(instr->index());
- LOperand* value = UseRegisterOrConstantAtStart(instr->value());
- return new(zone()) LSeqStringSetChar(string, index, value);
+ LOperand* index = FLAG_debug_code
+ ? UseRegisterAtStart(instr->index())
+ : UseRegisterOrConstantAtStart(instr->index());
+ LOperand* value = FLAG_debug_code
+ ? UseRegisterAtStart(instr->value())
+ : UseRegisterOrConstantAtStart(instr->value());
+ LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), rsi) : NULL;
+ LInstruction* result = new(zone()) LSeqStringSetChar(context, string,
+ index, value);
+ if (FLAG_debug_code) {
+ result = MarkAsCall(result, instr);
+ }
+ return result;
}
};
-class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
+class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> {
public:
- LSeqStringSetChar(LOperand* string,
+ LSeqStringSetChar(LOperand* context,
+ LOperand* string,
LOperand* index,
LOperand* value) {
- inputs_[0] = string;
- inputs_[1] = index;
- inputs_[2] = value;
+ inputs_[0] = context;
+ inputs_[1] = string;
+ inputs_[2] = index;
+ inputs_[3] = value;
}
- LOperand* string() { return inputs_[0]; }
- LOperand* index() { return inputs_[1]; }
- LOperand* value() { return inputs_[2]; }
+ LOperand* string() { return inputs_[1]; }
+ LOperand* index() { return inputs_[2]; }
+ LOperand* value() { return inputs_[3]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
}
+void MacroAssembler::Throw(BailoutReason reason) {
+#ifdef DEBUG
+ const char* msg = GetBailoutReason(reason);
+ if (msg != NULL) {
+ RecordComment("Throw message: ");
+ RecordComment(msg);
+ }
+#endif
+
+ push(rax);
+ Push(Smi::FromInt(reason));
+ if (!has_frame_) {
+ // We don't actually want to generate a pile of code for this, so just
+ // claim there is a stack frame, without generating one.
+ FrameScope scope(this, StackFrame::NONE);
+ CallRuntime(Runtime::kThrowMessage, 1);
+ } else {
+ CallRuntime(Runtime::kThrowMessage, 1);
+ }
+ // Control will not return here.
+ int3();
+}
+
+
+void MacroAssembler::ThrowIf(Condition cc, BailoutReason reason) {
+ Label L;
+ j(NegateCondition(cc), &L);
+ Throw(reason);
+ // will not return here
+ bind(&L);
+}
+
+
void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors) {
movq(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
}
+void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask) {
+ Label is_object;
+ JumpIfNotSmi(string, &is_object);
+ Throw(kNonObject);
+ bind(&is_object);
+
+ push(value);
+ movq(value, FieldOperand(string, HeapObject::kMapOffset));
+ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
+
+ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ cmpq(value, Immediate(encoding_mask));
+ pop(value);
+ ThrowIf(not_equal, kUnexpectedStringType);
+
+ // The index is assumed to be untagged coming in, tag it to compare with the
+ // string length without using a temp register, it is restored at the end of
+ // this function.
+ Integer32ToSmi(index, index);
+ SmiCompare(index, FieldOperand(string, String::kLengthOffset));
+ ThrowIf(greater_equal, kIndexIsTooLarge);
+
+ SmiCompare(index, Smi::FromInt(0));
+ ThrowIf(less, kIndexIsNegative);
+
+ // Restore the index
+ SmiToInteger32(index, index);
+}
+
+
void MacroAssembler::PrepareCallCFunction(int num_arguments) {
int frame_alignment = OS::ActivationFrameAlignment();
ASSERT(frame_alignment != 0);
Label* on_fail,
Label::Distance near_jump = Label::kFar);
+ void EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask);
+
// Checks if the given register or operand is a unique name
void JumpIfNotUniqueName(Register reg, Label* not_unique_name,
Label::Distance distance = Label::kFar);
// Propagate an uncatchable exception out of the current JS stack.
void ThrowUncatchable(Register value);
+ // Throw a message string as an exception.
+ void Throw(BailoutReason reason);
+
+ // Throw a message string as an exception if a condition is not true.
+ void ThrowIf(Condition cc, BailoutReason reason);
+
// ---------------------------------------------------------------------------
// Inline caching support
var knownProblems = {
"Abort": true,
+ "ThrowMessage": true,
// Avoid calling the concat operation, because weird lengths
// may lead to out-of-memory. Ditto for StringBuilderJoin.
var knownProblems = {
"Abort": true,
+ "ThrowMessage": true,
// Avoid calling the concat operation, because weird lengths
// may lead to out-of-memory. Ditto for StringBuilderJoin.
var knownProblems = {
"Abort": true,
+ "ThrowMessage": true,
// Avoid calling the concat operation, because weird lengths
// may lead to out-of-memory. Ditto for StringBuilderJoin.
var knownProblems = {
"Abort": true,
+ "ThrowMessage": true,
// Avoid calling the concat operation, because weird lengths
// may lead to out-of-memory. Ditto for StringBuilderJoin.
--- /dev/null
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --debug-code
+
+var one_byte = %NewString(10, true);
+var two_byte = %NewString(10, false);
+
+function foo1(s, arg1, arg2) {
+ return %_OneByteSeqStringSetChar(s, arg1, arg2)
+}
+foo1(one_byte, 0, 0);
+assertThrows("{ foo1(4, 0, 0); }");
+assertThrows("{ foo1(one_byte, new Object(), 0); }");
+assertThrows("{ foo1(one_byte, 0, new Object()); }");
+assertThrows("{ foo1(one_byte, 100000, 100; }");
+assertThrows("{ foo1(one_byte, -1, 100; }");
+
+function bar1(s, arg1, arg2) {
+ return %_OneByteSeqStringSetChar(s, arg1, arg2)
+}
+
+bar1(one_byte, 0, 0);
+bar1(one_byte, 0, 0);
+bar1(one_byte, 0, 0);
+%OptimizeFunctionOnNextCall(bar1);
+bar1(one_byte, 0, 0);
+assertThrows("{ bar1(4, 0, 0); }");
+assertThrows("{ bar1(one_byte, new Object(), 0); }");
+assertThrows("{ bar1(one_byte, 0, new Object()); }");
+assertThrows("{ bar1(one_byte, 100000, 100; }");
+assertThrows("{ bar1(one_byte, -1, 100; }");
+
+function foo2(s, arg1, arg2) {
+ return %_TwoByteSeqStringSetChar(s, arg1, arg2)
+}
+foo2(two_byte, 0, 0);
+assertThrows("{ foo2(4, 0, 0); }");
+assertThrows("{ foo2(two_byte, new Object(), 0); }");
+assertThrows("{ foo2(two_byte, 0, new Object()); }");
+assertThrows("{ foo2(two_byte, 100000, 100; }");
+assertThrows("{ foo2(two_byte, -1, 100; }");
+
+function bar2(s, arg1, arg2) {
+ return %_TwoByteSeqStringSetChar(s, arg1, arg2)
+}
+
+bar2(two_byte, 0, 0);
+bar2(two_byte, 0, 0);
+bar2(two_byte, 0, 0);
+%OptimizeFunctionOnNextCall(bar2);
+bar2(two_byte, 0, 0);
+assertThrows("{ bar2(4, 0, 0); }");
+assertThrows("{ bar2(two_byte, new Object(), 0); }");
+assertThrows("{ bar2(two_byte, 0, new Object()); }");
+assertThrows("{ bar2(two_byte, 100000, 100; }");
+assertThrows("{ bar2(two_byte, -1, 100; }");