}
+void BinaryOpICStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { r1, r0 };
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
+ descriptor->SetMissHandler(
+ ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
+}
+
+
static void InitializeArrayConstructorDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor,
}
-void BinaryOpICStub::InitializeInterfaceDescriptor(
- Isolate* isolate,
- CodeStubInterfaceDescriptor* descriptor) {
- static Register registers[] = { r1, r0 };
- descriptor->register_param_count_ = 2;
- descriptor->register_params_ = registers;
- descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
- descriptor->SetMissHandler(
- ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
-}
-
-
-void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
- Isolate* isolate,
- CodeStubInterfaceDescriptor* descriptor) {
- static Register registers[] = { r2, r1, r0 };
- descriptor->register_param_count_ = 3;
- descriptor->register_params_ = registers;
- descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
-}
-
-
void NewStringAddStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
- BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
}
}
-void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- r1 : left
- // -- r0 : right
- // -- lr : return address
- // -----------------------------------
- Isolate* isolate = masm->isolate();
-
- // Load r2 with the allocation site. We stick an undefined dummy value here
- // and replace it with the real allocation site later when we instantiate this
- // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
- __ Move(r2, handle(isolate->heap()->undefined_value()));
-
- // Make sure that we actually patched the allocation site.
- if (FLAG_debug_code) {
- __ tst(r2, Operand(kSmiTagMask));
- __ Assert(ne, kExpectedAllocationSite);
- __ push(r2);
- __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
- __ LoadRoot(ip, Heap::kAllocationSiteMapRootIndex);
- __ cmp(r2, ip);
- __ pop(r2);
- __ Assert(eq, kExpectedAllocationSite);
- }
-
- // Tail call into the stub that handles binary operations with allocation
- // sites.
- BinaryOpWithAllocationSiteStub stub(state_);
- __ TailCallStub(&stub);
-}
-
-
void StringAddStub::Generate(MacroAssembler* masm) {
Label call_runtime, call_builtin;
Builtins::JavaScript builtin_id = Builtins::ADD;
Token::Value op() const { return op_; }
Expression* left() const { return left_; }
Expression* right() const { return right_; }
- Handle<AllocationSite> allocation_site() const { return allocation_site_; }
- void set_allocation_site(Handle<AllocationSite> allocation_site) {
- allocation_site_ = allocation_site;
- }
BailoutId RightId() const { return right_id_; }
Token::Value op_;
Expression* left_;
Expression* right_;
- Handle<AllocationSite> allocation_site_;
// TODO(rossberg): the fixed arg should probably be represented as a Constant
// type for the RHS.
(state.HasSideEffects() || !result_type->Is(Type::None())));
HValue* result = NULL;
- HAllocationMode allocation_mode(NOT_TENURED);
if (state.op() == Token::ADD &&
(left_type->Maybe(Type::String()) || right_type->Maybe(Type::String())) &&
!left_type->Is(Type::String()) && !right_type->Is(Type::String())) {
Push(BuildBinaryOperation(
state.op(), left, right,
handle(Type::String(), isolate()), right_type,
- result_type, state.fixed_right_arg(),
- allocation_mode));
+ result_type, state.fixed_right_arg()));
}
if_leftisstring.Else();
{
Push(BuildBinaryOperation(
state.op(), left, right,
left_type, right_type, result_type,
- state.fixed_right_arg(), allocation_mode));
+ state.fixed_right_arg()));
}
if_leftisstring.End();
result = Pop();
Push(BuildBinaryOperation(
state.op(), left, right,
left_type, handle(Type::String(), isolate()),
- result_type, state.fixed_right_arg(),
- allocation_mode));
+ result_type, state.fixed_right_arg()));
}
if_rightisstring.Else();
{
Push(BuildBinaryOperation(
state.op(), left, right,
left_type, right_type, result_type,
- state.fixed_right_arg(), allocation_mode));
+ state.fixed_right_arg()));
}
if_rightisstring.End();
result = Pop();
result = BuildBinaryOperation(
state.op(), left, right,
left_type, right_type, result_type,
- state.fixed_right_arg(), allocation_mode);
+ state.fixed_right_arg());
}
// If we encounter a generic argument, the number conversion is
}
-template <>
-HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() {
- BinaryOpIC::State state = casted_stub()->state();
-
- HValue* allocation_site = GetParameter(
- BinaryOpWithAllocationSiteStub::kAllocationSite);
- HValue* left = GetParameter(BinaryOpWithAllocationSiteStub::kLeft);
- HValue* right = GetParameter(BinaryOpWithAllocationSiteStub::kRight);
-
- Handle<Type> left_type = state.GetLeftType(isolate());
- Handle<Type> right_type = state.GetRightType(isolate());
- Handle<Type> result_type = state.GetResultType(isolate());
- HAllocationMode allocation_mode(allocation_site);
-
- return BuildBinaryOperation(state.op(), left, right,
- left_type, right_type, result_type,
- state.fixed_right_arg(), allocation_mode);
-}
-
-
-Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode(Isolate* isolate) {
- return DoGenerateCode(isolate, this);
-}
-
-
template <>
HValue* CodeStubGraphBuilder<NewStringAddStub>::BuildCodeInitializedStub() {
NewStringAddStub* stub = casted_stub();
right = BuildCheckString(right);
}
- return BuildStringAdd(left, right, HAllocationMode(pretenure_flag));
+ return BuildStringAdd(left, right, pretenure_flag);
}
}
-// static
-void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
- // Generate special versions of the stub.
- BinaryOpIC::State::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
-}
-
-
-void BinaryOpICWithAllocationSiteStub::PrintState(StringStream* stream) {
- state_.Print(stream);
-}
-
-
-// static
-void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
- Isolate* isolate, const BinaryOpIC::State& state) {
- if (state.CouldCreateAllocationMementos()) {
- BinaryOpICWithAllocationSiteStub stub(state);
- stub.GetCode(isolate);
- }
-}
-
-
void NewStringAddStub::PrintBaseName(StringStream* stream) {
stream->Add("NewStringAddStub");
if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
V(CallFunction) \
V(CallConstruct) \
V(BinaryOpIC) \
- V(BinaryOpICWithAllocationSite) \
- V(BinaryOpWithAllocationSite) \
V(StringAdd) \
V(NewStringAdd) \
V(SubString) \
};
-class BinaryOpICStub : public HydrogenCodeStub {
+class BinaryOpICStub V8_FINAL : public HydrogenCodeStub {
public:
BinaryOpICStub(Token::Value op, OverwriteMode mode)
: HydrogenCodeStub(UNINITIALIZED), state_(op, mode) {}
return Code::BINARY_OP_IC;
}
- virtual InlineCacheState GetICState() V8_FINAL V8_OVERRIDE {
+ virtual InlineCacheState GetICState() V8_OVERRIDE {
return state_.GetICState();
}
- virtual ExtraICState GetExtraICState() V8_FINAL V8_OVERRIDE {
+ virtual ExtraICState GetExtraICState() V8_OVERRIDE {
return state_.GetExtraICState();
}
- virtual void VerifyPlatformFeatures(Isolate* isolate) V8_FINAL V8_OVERRIDE {
+ virtual void VerifyPlatformFeatures(Isolate* isolate) V8_OVERRIDE {
ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
}
const BinaryOpIC::State& state() const { return state_; }
- virtual void PrintState(StringStream* stream) V8_FINAL V8_OVERRIDE;
-
- virtual Major MajorKey() V8_OVERRIDE { return BinaryOpIC; }
- virtual int NotMissMinorKey() V8_FINAL V8_OVERRIDE {
- return GetExtraICState();
- }
+ virtual void PrintState(StringStream* stream) V8_OVERRIDE;
// Parameters accessed via CodeStubGraphBuilder::GetParameter()
static const int kLeft = 0;
static void GenerateAheadOfTime(Isolate* isolate,
const BinaryOpIC::State& state);
- BinaryOpIC::State state_;
-
- DISALLOW_COPY_AND_ASSIGN(BinaryOpICStub);
-};
-
-
-// TODO(bmeurer): Merge this into the BinaryOpICStub once we have proper tail
-// call support for stubs in Hydrogen.
-class BinaryOpICWithAllocationSiteStub V8_FINAL : public PlatformCodeStub {
- public:
- explicit BinaryOpICWithAllocationSiteStub(const BinaryOpIC::State& state)
- : state_(state) {}
-
- static void GenerateAheadOfTime(Isolate* isolate);
-
- Handle<Code> GetCodeCopyFromTemplate(Isolate* isolate,
- Handle<AllocationSite> allocation_site) {
- Handle<Code> code = CodeStub::GetCodeCopyFromTemplate(isolate);
- // Replace the placeholder oddball with the actual allocation site.
- code->ReplaceNthObject(1, isolate->heap()->oddball_map(), *allocation_site);
- return code;
- }
-
- virtual Code::Kind GetCodeKind() const V8_OVERRIDE {
- return Code::BINARY_OP_IC;
- }
-
- virtual InlineCacheState GetICState() V8_OVERRIDE {
- return state_.GetICState();
- }
-
- virtual ExtraICState GetExtraICState() V8_OVERRIDE {
- return state_.GetExtraICState();
- }
-
- virtual void VerifyPlatformFeatures(Isolate* isolate) V8_OVERRIDE {
- ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
- }
-
- virtual void Generate(MacroAssembler* masm) V8_OVERRIDE;
-
- virtual void PrintState(StringStream* stream) V8_OVERRIDE;
-
- virtual Major MajorKey() V8_OVERRIDE { return BinaryOpICWithAllocationSite; }
- virtual int MinorKey() V8_OVERRIDE { return GetExtraICState(); }
-
- private:
- static void GenerateAheadOfTime(Isolate* isolate,
- const BinaryOpIC::State& state);
+ virtual Major MajorKey() V8_OVERRIDE { return BinaryOpIC; }
+ virtual int NotMissMinorKey() V8_OVERRIDE { return GetExtraICState(); }
BinaryOpIC::State state_;
- DISALLOW_COPY_AND_ASSIGN(BinaryOpICWithAllocationSiteStub);
-};
-
-
-class BinaryOpWithAllocationSiteStub V8_FINAL : public BinaryOpICStub {
- public:
- explicit BinaryOpWithAllocationSiteStub(const BinaryOpIC::State& state)
- : BinaryOpICStub(state) {}
-
- virtual void InitializeInterfaceDescriptor(
- Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
-
- static void InstallDescriptors(Isolate* isolate);
-
- virtual Code::Kind GetCodeKind() const V8_FINAL V8_OVERRIDE {
- return Code::STUB;
- }
-
- virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
-
- virtual Major MajorKey() V8_OVERRIDE {
- return BinaryOpWithAllocationSite;
- }
-
- // Parameters accessed via CodeStubGraphBuilder::GetParameter()
- static const int kAllocationSite = 0;
- static const int kLeft = 1;
- static const int kRight = 2;
+ DISALLOW_COPY_AND_ASSIGN(BinaryOpICStub);
};
return PretenureFlagBits::decode(bit_field_);
}
- virtual void VerifyPlatformFeatures(Isolate* isolate) V8_OVERRIDE {
- ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
- }
-
virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
virtual void InitializeInterfaceDescriptor(
HValue* context,
HValue* left,
HValue* right,
- PretenureFlag pretenure_flag,
- StringAddFlags flags,
- Handle<AllocationSite> allocation_site) {
+ StringAddFlags flags) {
if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
HConstant* c_right = HConstant::cast(right);
HConstant* c_left = HConstant::cast(left);
return HConstant::New(zone, context, concat);
}
}
- return new(zone) HStringAdd(
- context, left, right, pretenure_flag, flags, allocation_site);
-}
-
-
-void HStringAdd::PrintDataTo(StringStream* stream) {
- if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
- stream->Add("_CheckBoth");
- } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_LEFT) {
- stream->Add("_CheckLeft");
- } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_RIGHT) {
- stream->Add("_CheckRight");
- }
- stream->Add(" (");
- if (pretenure_flag() == NOT_TENURED) stream->Add("N");
- else if (pretenure_flag() == TENURED) stream->Add("D");
- stream->Add(")");
+ return new(zone) HStringAdd(context, left, right, flags);
}
HValue* context,
HValue* left,
HValue* right,
- PretenureFlag pretenure_flag = NOT_TENURED,
- StringAddFlags flags = STRING_ADD_CHECK_BOTH,
- Handle<AllocationSite> allocation_site =
- Handle<AllocationSite>::null());
+ StringAddFlags flags = STRING_ADD_CHECK_NONE);
StringAddFlags flags() const { return flags_; }
- PretenureFlag pretenure_flag() const { return pretenure_flag_; }
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
return Representation::Tagged();
}
- virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
-
DECLARE_CONCRETE_INSTRUCTION(StringAdd)
protected:
- virtual bool DataEquals(HValue* other) V8_OVERRIDE {
- return flags_ == HStringAdd::cast(other)->flags_ &&
- pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
- }
+ virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
private:
- HStringAdd(HValue* context,
- HValue* left,
- HValue* right,
- PretenureFlag pretenure_flag,
- StringAddFlags flags,
- Handle<AllocationSite> allocation_site)
- : HBinaryOperation(context, left, right, HType::String()),
- flags_(flags), pretenure_flag_(pretenure_flag) {
+ HStringAdd(HValue* context, HValue* left, HValue* right, StringAddFlags flags)
+ : HBinaryOperation(context, left, right, HType::String()), flags_(flags) {
set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnMaps);
- SetGVNFlag(kChangesNewSpacePromotion);
- if (FLAG_trace_pretenuring) {
- PrintF("HStringAdd with AllocationSite %p %s\n",
- allocation_site.is_null()
- ? static_cast<void*>(NULL)
- : static_cast<void*>(*allocation_site),
- pretenure_flag == TENURED ? "tenured" : "not tenured");
+ if (MightHaveSideEffects()) {
+ SetAllSideEffects();
+ } else {
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
}
+ bool MightHaveSideEffects() const {
+ return flags_ != STRING_ADD_CHECK_NONE &&
+ (left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved());
+ }
+
// No side-effects except possible allocation:
- virtual bool IsDeletable() const V8_OVERRIDE { return true; }
+ // NOTE: this instruction does not call ToString() on its inputs, when flags_
+ // is set to STRING_ADD_CHECK_NONE.
+ virtual bool IsDeletable() const V8_OVERRIDE {
+ return !MightHaveSideEffects();
+ }
const StringAddFlags flags_;
- const PretenureFlag pretenure_flag_;
};
}
-HAllocate* HGraphBuilder::BuildAllocate(
- HValue* object_size,
- HType type,
- InstanceType instance_type,
- HAllocationMode allocation_mode) {
- // Compute the effective allocation size.
- HValue* size = object_size;
- if (allocation_mode.CreateAllocationMementos()) {
- size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize));
+HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length,
+ String::Encoding encoding) {
+ STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
+ HValue* size = length;
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ size = AddUncasted<HShl>(length, graph()->GetConstant1());
size->ClearFlag(HValue::kCanOverflow);
+ size->SetFlag(HValue::kUint32);
}
-
- // Perform the actual allocation.
- HAllocate* object = Add<HAllocate>(
- size, type, allocation_mode.GetPretenureMode(),
- instance_type, allocation_mode.feedback_site());
-
- // Setup the allocation memento.
- if (allocation_mode.CreateAllocationMementos()) {
- BuildCreateAllocationMemento(
- object, object_size, allocation_mode.current_site());
- }
-
- return object;
-}
-
-
-HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length,
- HValue* right_length) {
- // Compute the combined string length. If the result is larger than the max
- // supported string length, we bailout to the runtime. This is done implicitly
- // when converting the result back to a smi in case the max string length
- // equals the max smi value. Otherwise, for platforms with 32-bit smis, we do
- HValue* length = AddUncasted<HAdd>(left_length, right_length);
- STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
- if (String::kMaxLength != Smi::kMaxValue) {
- IfBuilder if_nooverflow(this);
- if_nooverflow.If<HCompareNumericAndBranch>(
- length, Add<HConstant>(String::kMaxLength), Token::LTE);
- if_nooverflow.Then();
- if_nooverflow.ElseDeopt("String length exceeds limit");
- }
- return length;
-}
-
-
-HValue* HGraphBuilder::BuildCreateConsString(
- HValue* length,
- HValue* left,
- HValue* right,
- HAllocationMode allocation_mode) {
- // Determine the string instance types.
- HInstruction* left_instance_type = AddLoadStringInstanceType(left);
- HInstruction* right_instance_type = AddLoadStringInstanceType(right);
-
- // Allocate the cons string object. HAllocate does not care whether we
- // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use
- // CONS_STRING_TYPE here. Below we decide whether the cons string is
- // one-byte or two-byte and set the appropriate map.
- ASSERT(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE,
- CONS_ASCII_STRING_TYPE));
- HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize),
- HType::String(), CONS_STRING_TYPE,
- allocation_mode);
-
- // Compute intersection and difference of instance types.
- HValue* anded_instance_types = AddUncasted<HBitwise>(
- Token::BIT_AND, left_instance_type, right_instance_type);
- HValue* xored_instance_types = AddUncasted<HBitwise>(
- Token::BIT_XOR, left_instance_type, right_instance_type);
-
- // We create a one-byte cons string if
- // 1. both strings are one-byte, or
- // 2. at least one of the strings is two-byte, but happens to contain only
- // one-byte characters.
- // To do this, we check
- // 1. if both strings are one-byte, or if the one-byte data hint is set in
- // both strings, or
- // 2. if one of the strings has the one-byte data hint set and the other
- // string is one-byte.
- IfBuilder if_onebyte(this);
- STATIC_ASSERT(kOneByteStringTag != 0);
- STATIC_ASSERT(kOneByteDataHintMask != 0);
- if_onebyte.If<HCompareNumericAndBranch>(
- AddUncasted<HBitwise>(
- Token::BIT_AND, anded_instance_types,
- Add<HConstant>(static_cast<int32_t>(
- kStringEncodingMask | kOneByteDataHintMask))),
- graph()->GetConstant0(), Token::NE);
- if_onebyte.Or();
- STATIC_ASSERT(kOneByteStringTag != 0 &&
- kOneByteDataHintTag != 0 &&
- kOneByteDataHintTag != kOneByteStringTag);
- if_onebyte.If<HCompareNumericAndBranch>(
- AddUncasted<HBitwise>(
- Token::BIT_AND, xored_instance_types,
- Add<HConstant>(static_cast<int32_t>(
- kOneByteStringTag | kOneByteDataHintTag))),
- Add<HConstant>(static_cast<int32_t>(
- kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
- if_onebyte.Then();
- {
- // We can safely skip the write barrier for storing the map here.
- Handle<Map> map = isolate()->factory()->cons_ascii_string_map();
- AddStoreMapConstantNoWriteBarrier(result, map);
- }
- if_onebyte.Else();
- {
- // We can safely skip the write barrier for storing the map here.
- Handle<Map> map = isolate()->factory()->cons_string_map();
- AddStoreMapConstantNoWriteBarrier(result, map);
- }
- if_onebyte.End();
-
- // Initialize the cons string fields.
- Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
- Add<HConstant>(String::kEmptyHashField));
- Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
- Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left);
- Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right);
-
- // Count the native string addition.
- AddIncrementCounter(isolate()->counters()->string_add_native());
-
- return result;
+ size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
+ SeqString::kHeaderSize + kObjectAlignmentMask)));
+ size->ClearFlag(HValue::kCanOverflow);
+ size = AddUncasted<HBitwise>(
+ Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
+ ~kObjectAlignmentMask)));
+ return size;
}
}
-HValue* HGraphBuilder::BuildUncheckedStringAdd(
- HValue* left,
- HValue* right,
- HAllocationMode allocation_mode) {
+HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
+ HValue* right,
+ PretenureFlag pretenure_flag) {
// Determine the string lengths.
- HValue* left_length = AddLoadStringLength(left);
- HValue* right_length = AddLoadStringLength(right);
+ HValue* left_length = Add<HLoadNamedField>(
+ left, HObjectAccess::ForStringLength());
+ HValue* right_length = Add<HLoadNamedField>(
+ right, HObjectAccess::ForStringLength());
- // Compute the combined string length.
- HValue* length = BuildAddStringLengths(left_length, right_length);
-
- // Do some manual constant folding here.
- if (left_length->IsConstant()) {
- HConstant* c_left_length = HConstant::cast(left_length);
- ASSERT_NE(0, c_left_length->Integer32Value());
- if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) {
- // The right string contains at least one character.
- return BuildCreateConsString(length, left, right, allocation_mode);
- }
- } else if (right_length->IsConstant()) {
- HConstant* c_right_length = HConstant::cast(right_length);
- ASSERT_NE(0, c_right_length->Integer32Value());
- if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) {
- // The left string contains at least one character.
- return BuildCreateConsString(length, left, right, allocation_mode);
- }
+ // Compute the combined string length. If the result is larger than the max
+ // supported string length, we bailout to the runtime. This is done implicitly
+ // when converting the result back to a smi in case the max string length
+ // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do
+ HValue* length = AddUncasted<HAdd>(left_length, right_length);
+ STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
+ if (String::kMaxLength != Smi::kMaxValue) {
+ IfBuilder if_nooverflow(this);
+ if_nooverflow.If<HCompareNumericAndBranch>(
+ length, Add<HConstant>(String::kMaxLength), Token::LTE);
+ if_nooverflow.Then();
+ if_nooverflow.ElseDeopt("String length exceeds limit");
}
+ // Determine the string instance types.
+ HLoadNamedField* left_instance_type = Add<HLoadNamedField>(
+ Add<HLoadNamedField>(left, HObjectAccess::ForMap()),
+ HObjectAccess::ForMapInstanceType());
+ HLoadNamedField* right_instance_type = Add<HLoadNamedField>(
+ Add<HLoadNamedField>(right, HObjectAccess::ForMap()),
+ HObjectAccess::ForMapInstanceType());
+
+ // Compute difference of instance types.
+ HValue* xored_instance_types = AddUncasted<HBitwise>(
+ Token::BIT_XOR, left_instance_type, right_instance_type);
+
// Check if we should create a cons string.
IfBuilder if_createcons(this);
if_createcons.If<HCompareNumericAndBranch>(
length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
if_createcons.Then();
{
- // Create a cons string.
- Push(BuildCreateConsString(length, left, right, allocation_mode));
+ // Allocate the cons string object. HAllocate does not care whether we
+ // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use
+ // CONS_STRING_TYPE here. Below we decide whether the cons string is
+ // one-byte or two-byte and set the appropriate map.
+ ASSERT(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE,
+ CONS_ASCII_STRING_TYPE));
+ HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize),
+ HType::String(), pretenure_flag,
+ CONS_STRING_TYPE);
+
+ // Compute the intersection of instance types.
+ HValue* anded_instance_types = AddUncasted<HBitwise>(
+ Token::BIT_AND, left_instance_type, right_instance_type);
+
+ // We create a one-byte cons string if
+ // 1. both strings are one-byte, or
+ // 2. at least one of the strings is two-byte, but happens to contain only
+ // one-byte characters.
+ // To do this, we check
+ // 1. if both strings are one-byte, or if the one-byte data hint is set in
+ // both strings, or
+ // 2. if one of the strings has the one-byte data hint set and the other
+ // string is one-byte.
+ IfBuilder if_onebyte(this);
+ STATIC_ASSERT(kOneByteStringTag != 0);
+ STATIC_ASSERT(kOneByteDataHintMask != 0);
+ if_onebyte.If<HCompareNumericAndBranch>(
+ AddUncasted<HBitwise>(
+ Token::BIT_AND, anded_instance_types,
+ Add<HConstant>(static_cast<int32_t>(
+ kStringEncodingMask | kOneByteDataHintMask))),
+ graph()->GetConstant0(), Token::NE);
+ if_onebyte.Or();
+ STATIC_ASSERT(kOneByteStringTag != 0 &&
+ kOneByteDataHintTag != 0 &&
+ kOneByteDataHintTag != kOneByteStringTag);
+ if_onebyte.If<HCompareNumericAndBranch>(
+ AddUncasted<HBitwise>(
+ Token::BIT_AND, xored_instance_types,
+ Add<HConstant>(static_cast<int32_t>(
+ kOneByteStringTag | kOneByteDataHintTag))),
+ Add<HConstant>(static_cast<int32_t>(
+ kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
+ if_onebyte.Then();
+ {
+ // We can safely skip the write barrier for storing the map here.
+ Handle<Map> map = isolate()->factory()->cons_ascii_string_map();
+ AddStoreMapConstantNoWriteBarrier(string, map);
+ }
+ if_onebyte.Else();
+ {
+ // We can safely skip the write barrier for storing the map here.
+ Handle<Map> map = isolate()->factory()->cons_string_map();
+ AddStoreMapConstantNoWriteBarrier(string, map);
+ }
+ if_onebyte.End();
+
+ // Initialize the cons string fields.
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+ Add<HConstant>(String::kEmptyHashField));
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length);
+ Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left);
+ Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(),
+ right);
+
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
+
+ // Cons string is result.
+ Push(string);
}
if_createcons.Else();
{
- // Determine the string instance types.
- HValue* left_instance_type = AddLoadStringInstanceType(left);
- HValue* right_instance_type = AddLoadStringInstanceType(right);
-
- // Compute union and difference of instance types.
+ // Compute union of instance types.
HValue* ored_instance_types = AddUncasted<HBitwise>(
Token::BIT_OR, left_instance_type, right_instance_type);
- HValue* xored_instance_types = AddUncasted<HBitwise>(
- Token::BIT_XOR, left_instance_type, right_instance_type);
// Check if both strings have the same encoding and both are
// sequential.
graph()->GetConstant0(), Token::EQ);
if_sameencodingandsequential.Then();
{
- HConstant* string_map =
- Add<HConstant>(isolate()->factory()->string_map());
- HConstant* ascii_string_map =
- Add<HConstant>(isolate()->factory()->ascii_string_map());
-
- // Determine map and size depending on whether result is one-byte string.
+ // Check if the result is a one-byte string.
IfBuilder if_onebyte(this);
STATIC_ASSERT(kOneByteStringTag != 0);
if_onebyte.If<HCompareNumericAndBranch>(
graph()->GetConstant0(), Token::NE);
if_onebyte.Then();
{
- // Allocate sequential one-byte string object.
- Push(length);
- Push(ascii_string_map);
- }
- if_onebyte.Else();
- {
- // Allocate sequential two-byte string object.
- HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1());
- size->ClearFlag(HValue::kCanOverflow);
- size->SetFlag(HValue::kUint32);
- Push(size);
- Push(string_map);
- }
- if_onebyte.End();
- HValue* map = Pop();
-
- // Calculate the number of bytes needed for the characters in the
- // string while observing object alignment.
- STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
- HValue* size = Pop();
- size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
- SeqString::kHeaderSize + kObjectAlignmentMask)));
- size->ClearFlag(HValue::kCanOverflow);
- size = AddUncasted<HBitwise>(
- Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
- ~kObjectAlignmentMask)));
-
- // Allocate the string object. HAllocate does not care whether we pass
- // STRING_TYPE or ASCII_STRING_TYPE here, so we just use STRING_TYPE here.
- HAllocate* result = BuildAllocate(
- size, HType::String(), STRING_TYPE, allocation_mode);
-
- // We can safely skip the write barrier for storing map here.
- AddStoreMapNoWriteBarrier(result, map);
-
- // Initialize the string fields.
- Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
- Add<HConstant>(String::kEmptyHashField));
- Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
-
- // Copy characters to the result string.
- IfBuilder if_twobyte(this);
- if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map);
- if_twobyte.Then();
- {
- // Copy characters from the left string.
+ // Calculate the number of bytes needed for the characters in the
+ // string while observing object alignment.
+ HValue* size = BuildSeqStringSizeFor(
+ length, String::ONE_BYTE_ENCODING);
+
+ // Allocate the ASCII string object.
+ Handle<Map> map = isolate()->factory()->ascii_string_map();
+ HAllocate* string = Add<HAllocate>(size, HType::String(),
+ pretenure_flag, ASCII_STRING_TYPE);
+ string->set_known_initial_map(map);
+
+ // 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,
- result, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+ left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
left_length);
- // Copy characters from the right string.
+ // Copy bytes from the right string.
BuildCopySeqStringChars(
- right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
- result, left_length, String::TWO_BYTE_ENCODING,
+ right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ string, left_length, String::ONE_BYTE_ENCODING,
right_length);
+
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
+
+ // Return the string.
+ Push(string);
}
- if_twobyte.Else();
+ if_onebyte.Else();
{
- // Copy characters from the left string.
+ // Calculate the number of bytes needed for the characters in the
+ // string while observing object alignment.
+ HValue* size = BuildSeqStringSizeFor(
+ length, String::TWO_BYTE_ENCODING);
+
+ // Allocate the two-byte string object.
+ Handle<Map> map = isolate()->factory()->string_map();
+ HAllocate* string = Add<HAllocate>(size, HType::String(),
+ pretenure_flag, STRING_TYPE);
+ string->set_known_initial_map(map);
+
+ // 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,
- result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+ string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
left_length);
- // Copy characters from the right string.
+ // Copy bytes from the right string.
BuildCopySeqStringChars(
- right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
- result, left_length, String::ONE_BYTE_ENCODING,
+ right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+ string, left_length, String::TWO_BYTE_ENCODING,
right_length);
+
+ // Return the string.
+ Push(string);
}
- if_twobyte.End();
+ if_onebyte.End();
+
+ // Initialize the (common) string fields.
+ HValue* string = Pop();
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+ Add<HConstant>(String::kEmptyHashField));
// Count the native string addition.
AddIncrementCounter(isolate()->counters()->string_add_native());
- // Return the sequential string.
- Push(result);
+ Push(string);
}
if_sameencodingandsequential.Else();
{
}
-HValue* HGraphBuilder::BuildStringAdd(
- HValue* left,
- HValue* right,
- HAllocationMode allocation_mode) {
- NoObservableSideEffectsScope no_effects(this);
-
- // Determine string lengths.
- HValue* left_length = AddLoadStringLength(left);
- HValue* right_length = AddLoadStringLength(right);
+HValue* HGraphBuilder::BuildStringAdd(HValue* left,
+ HValue* right,
+ PretenureFlag pretenure_flag) {
+ // Determine the string lengths.
+ HValue* left_length = Add<HLoadNamedField>(
+ left, HObjectAccess::ForStringLength());
+ HValue* right_length = Add<HLoadNamedField>(
+ right, HObjectAccess::ForStringLength());
// Check if left string is empty.
- IfBuilder if_leftempty(this);
- if_leftempty.If<HCompareNumericAndBranch>(
+ IfBuilder if_leftisempty(this);
+ if_leftisempty.If<HCompareNumericAndBranch>(
left_length, graph()->GetConstant0(), Token::EQ);
- if_leftempty.Then();
+ if_leftisempty.Then();
{
// Count the native string addition.
AddIncrementCounter(isolate()->counters()->string_add_native());
// Just return the right string.
Push(right);
}
- if_leftempty.Else();
+ if_leftisempty.Else();
{
// Check if right string is empty.
- IfBuilder if_rightempty(this);
- if_rightempty.If<HCompareNumericAndBranch>(
+ IfBuilder if_rightisempty(this);
+ if_rightisempty.If<HCompareNumericAndBranch>(
right_length, graph()->GetConstant0(), Token::EQ);
- if_rightempty.Then();
+ if_rightisempty.Then();
{
// Count the native string addition.
AddIncrementCounter(isolate()->counters()->string_add_native());
// Just return the left string.
Push(left);
}
- if_rightempty.Else();
+ if_rightisempty.Else();
{
- // Add the two non-empty strings.
- Push(BuildUncheckedStringAdd(left, right, allocation_mode));
+ // Concatenate the two non-empty strings.
+ Push(BuildUncheckedStringAdd(left, right, pretenure_flag));
}
- if_rightempty.End();
+ if_rightisempty.End();
}
- if_leftempty.End();
+ if_leftisempty.End();
return Pop();
}
}
-HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) {
- if (string->IsConstant()) {
- HConstant* c_string = HConstant::cast(string);
- if (c_string->HasStringValue()) {
- return Add<HConstant>(c_string->StringValue()->map()->instance_type());
+HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object,
+ HValue* checked_string) {
+ if (FLAG_fold_constants && object->IsConstant()) {
+ HConstant* constant = HConstant::cast(object);
+ if (constant->HasStringValue()) {
+ return New<HConstant>(constant->StringValue()->length());
}
}
- return AddLoadNamedField(
- AddLoadNamedField(string, HObjectAccess::ForMap()),
- HObjectAccess::ForMapInstanceType());
-}
-
-
-HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) {
- if (string->IsConstant()) {
- HConstant* c_string = HConstant::cast(string);
- if (c_string->HasStringValue()) {
- return Add<HConstant>(c_string->StringValue()->length());
- }
- }
- return AddLoadNamedField(string, HObjectAccess::ForStringLength());
+ return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength());
}
return New<HConstant>(s->Get(i));
}
}
- string = BuildCheckString(string);
- index = Add<HBoundsCheck>(index, AddLoadStringLength(string));
- return New<HStringCharCodeAt>(string, index);
+ BuildCheckHeapObject(string);
+ HValue* checkstring =
+ Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
+ HInstruction* length = BuildLoadStringLength(string, checkstring);
+ AddInstruction(length);
+ HInstruction* checked_index = Add<HBoundsCheck>(index, length);
+ return New<HStringCharCodeAt>(string, checked_index);
}
Handle<Type> right_type = expr->right()->bounds().lower;
Handle<Type> result_type = expr->bounds().lower;
Maybe<int> fixed_right_arg = expr->fixed_right_arg();
- Handle<AllocationSite> allocation_site = expr->allocation_site();
-
- HAllocationMode allocation_mode =
- FLAG_allocation_site_pretenuring
- ? (allocation_site.is_null()
- ? HAllocationMode(NOT_TENURED)
- : HAllocationMode(allocation_site))
- : HAllocationMode(isolate()->heap()->GetPretenureMode());
HValue* result = HGraphBuilder::BuildBinaryOperation(
- expr->op(), left, right, left_type, right_type, result_type,
- fixed_right_arg, allocation_mode);
+ expr->op(), left, right, left_type, right_type,
+ result_type, fixed_right_arg);
// Add a simulate after instructions with observable side effects, and
// after phis, which are the result of BuildBinaryOperation when we
// inlined some complex subgraph.
Handle<Type> left_type,
Handle<Type> right_type,
Handle<Type> result_type,
- Maybe<int> fixed_right_arg,
- HAllocationMode allocation_mode) {
+ Maybe<int> fixed_right_arg) {
Representation left_rep = Representation::FromType(left_type);
Representation right_rep = Representation::FromType(right_type);
return AddUncasted<HInvokeFunction>(function, 2);
}
- // Inline the string addition into the stub when creating allocation
- // mementos to gather allocation site feedback.
- if (graph()->info()->IsStub() &&
- allocation_mode.CreateAllocationMementos()) {
- return BuildStringAdd(left, right, allocation_mode);
- }
-
- // Register the dependent code with the allocation site.
- if (!allocation_mode.feedback_site().is_null()) {
- ASSERT(!graph()->info()->IsStub());
- allocation_mode.feedback_site()->AddDependentCompilationInfo(
- AllocationSite::TENURING, top_info());
- }
-
- // Inline string addition if we know that we'll create a cons string.
- if (left->IsConstant()) {
- HConstant* c_left = HConstant::cast(left);
- if (c_left->HasStringValue()) {
- int c_left_length = c_left->StringValue()->length();
- if (c_left_length == 0) {
- return right;
- } else if (c_left_length + 1 >= ConsString::kMinLength) {
- return BuildStringAdd(left, right, allocation_mode);
- }
- }
- }
- if (right->IsConstant()) {
- HConstant* c_right = HConstant::cast(right);
- if (c_right->HasStringValue()) {
- int c_right_length = c_right->StringValue()->length();
- if (c_right_length == 0) {
- return left;
- } else if (c_right_length + 1 >= ConsString::kMinLength) {
- return BuildStringAdd(left, right, allocation_mode);
- }
- }
- }
-
- // Fallback to using the string add stub.
- return AddUncasted<HStringAdd>(
- left, right, allocation_mode.GetPretenureMode(),
- STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
+ return AddUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE);
}
if (graph()->info()->IsStub()) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
HValue* right = Pop();
HValue* left = Pop();
- HInstruction* result = NewUncasted<HStringAdd>(left, right);
+ HInstruction* result =
+ NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH);
return ast_context()->ReturnInstruction(result, call->id());
}
};
-class HAllocationMode V8_FINAL BASE_EMBEDDED {
- public:
- explicit HAllocationMode(Handle<AllocationSite> feedback_site)
- : current_site_(NULL), feedback_site_(feedback_site),
- pretenure_flag_(NOT_TENURED) {}
- explicit HAllocationMode(HValue* current_site)
- : current_site_(current_site), pretenure_flag_(NOT_TENURED) {}
- explicit HAllocationMode(PretenureFlag pretenure_flag)
- : current_site_(NULL), pretenure_flag_(pretenure_flag) {}
-
- HValue* current_site() const { return current_site_; }
- Handle<AllocationSite> feedback_site() const { return feedback_site_; }
-
- bool CreateAllocationMementos() const V8_WARN_UNUSED_RESULT {
- return current_site() != NULL;
- }
-
- PretenureFlag GetPretenureMode() const V8_WARN_UNUSED_RESULT {
- if (!feedback_site().is_null()) return feedback_site()->GetPretenureMode();
- return pretenure_flag_;
- }
-
- private:
- HValue* current_site_;
- Handle<AllocationSite> feedback_site_;
- PretenureFlag pretenure_flag_;
-};
-
-
class HGraphBuilder {
public:
explicit HGraphBuilder(CompilationInfo* info)
HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver,
HValue* key);
- // Allocates a new object according with the given allocation properties.
- HAllocate* BuildAllocate(HValue* object_size,
- HType type,
- InstanceType instance_type,
- HAllocationMode allocation_mode);
- // Computes the sum of two string lengths, taking care of overflow handling.
- HValue* BuildAddStringLengths(HValue* left_length, HValue* right_length);
- // Creates a cons string using the two input strings.
- HValue* BuildCreateConsString(HValue* length,
- HValue* left,
- HValue* right,
- HAllocationMode allocation_mode);
+ // Computes the size for a sequential string of the given length and encoding.
+ HValue* BuildSeqStringSizeFor(HValue* length,
+ String::Encoding encoding);
// Copies characters from one sequential string to another.
void BuildCopySeqStringChars(HValue* src,
HValue* src_offset,
// Both operands are non-empty strings.
HValue* BuildUncheckedStringAdd(HValue* left,
HValue* right,
- HAllocationMode allocation_mode);
- // Add two strings using allocation mode, validating type feedback.
+ PretenureFlag pretenure_flag);
+ // Both operands are strings.
HValue* BuildStringAdd(HValue* left,
HValue* right,
- HAllocationMode allocation_mode);
+ PretenureFlag pretenure_flag);
HInstruction* BuildUncheckedMonomorphicElementAccess(
HValue* checked_object,
HLoadNamedField* BuildLoadNamedField(HValue* object, HObjectAccess access);
HInstruction* AddLoadNamedField(HValue* object, HObjectAccess access);
- HInstruction* AddLoadStringInstanceType(HValue* string);
- HInstruction* AddLoadStringLength(HValue* string);
- HStoreNamedField* AddStoreMapNoWriteBarrier(HValue* object, HValue* map) {
- HStoreNamedField* store_map = Add<HStoreNamedField>(
- object, HObjectAccess::ForMap(), map);
- store_map->SkipWriteBarrier();
- return store_map;
- }
+ HInstruction* BuildLoadStringLength(HValue* object, HValue* checked_value);
HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map);
HStoreNamedField* AddStoreMapConstantNoWriteBarrier(HValue* object,
Handle<Map> map) {
Handle<Type> left_type,
Handle<Type> right_type,
Handle<Type> result_type,
- Maybe<int> fixed_right_arg,
- HAllocationMode allocation_mode);
+ Maybe<int> fixed_right_arg);
HLoadNamedField* AddLoadFixedArrayLength(HValue *object);
}
-void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
- Isolate* isolate,
- CodeStubInterfaceDescriptor* descriptor) {
- static Register registers[] = { ecx, edx, eax };
- descriptor->register_param_count_ = 3;
- descriptor->register_params_ = registers;
- descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
-}
-
-
void NewStringAddStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
if (Serializer::enabled()) {
PlatformFeatureScope sse2(SSE2);
BinaryOpICStub::GenerateAheadOfTime(isolate);
- BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
} else {
BinaryOpICStub::GenerateAheadOfTime(isolate);
- BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
}
}
}
-void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- edx : left
- // -- eax : right
- // -- esp[0] : return address
- // -----------------------------------
- Isolate* isolate = masm->isolate();
-
- // Load ecx with the allocation site. We stick an undefined dummy value here
- // and replace it with the real allocation site later when we instantiate this
- // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
- __ mov(ecx, handle(isolate->heap()->undefined_value()));
-
- // Make sure that we actually patched the allocation site.
- if (FLAG_debug_code) {
- __ test(ecx, Immediate(kSmiTagMask));
- __ Assert(not_equal, kExpectedAllocationSite);
- __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
- isolate->factory()->allocation_site_map());
- __ Assert(equal, kExpectedAllocationSite);
- }
-
- // Tail call into the stub that handles binary operations with allocation
- // sites.
- BinaryOpWithAllocationSiteStub stub(state_);
- __ TailCallStub(&stub);
-}
-
-
void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
ASSERT(state_ == CompareIC::SMI);
Label miss;
ASSERT(ToRegister(instr->left()).is(edx));
ASSERT(ToRegister(instr->right()).is(eax));
NewStringAddStub stub(instr->hydrogen()->flags(),
- instr->hydrogen()->pretenure_flag());
+ isolate()->heap()->GetPretenureMode());
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else {
EmitPushTaggedOperand(instr->left());
GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
GENERATE(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT);
GENERATE(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT);
- GENERATE(Token::ADD, STRING, SMI, STRING, NO_OVERWRITE);
- GENERATE(Token::ADD, SMI, STRING, STRING, NO_OVERWRITE);
- GENERATE(Token::ADD, STRING, NUMBER, STRING, NO_OVERWRITE);
- GENERATE(Token::ADD, NUMBER, STRING, STRING, NO_OVERWRITE);
- GENERATE(Token::ADD, STRING, STRING, STRING, NO_OVERWRITE);
GENERATE(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE);
GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT);
GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT);
stream->Add("(%s", Token::Name(op_));
if (mode_ == OVERWRITE_LEFT) stream->Add("_ReuseLeft");
else if (mode_ == OVERWRITE_RIGHT) stream->Add("_ReuseRight");
- if (CouldCreateAllocationMementos()) stream->Add("_CreateAllocationMementos");
stream->Add(":%s*", KindToString(left_kind_));
if (fixed_right_arg_.has_value) {
stream->Add("%d", fixed_right_arg_.value);
}
}
- // We don't want to distinguish INT32 and NUMBER for string add (because
- // NumberToString can't make use of this anyway).
- if (left_kind_ == STRING && right_kind_ == INT32) {
- ASSERT_EQ(STRING, result_kind_);
- ASSERT_EQ(Token::ADD, op_);
- right_kind_ = NUMBER;
- } else if (right_kind_ == STRING && left_kind_ == INT32) {
- ASSERT_EQ(STRING, result_kind_);
- ASSERT_EQ(Token::ADD, op_);
- left_kind_ = NUMBER;
- }
-
// Reset overwrite mode unless we can actually make use of it, or may be able
// to make use of it at some point in the future.
if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) ||
}
-MaybeObject* BinaryOpIC::Transition(Handle<AllocationSite> allocation_site,
- Handle<Object> left,
- Handle<Object> right) {
+MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
State state(target()->extended_extra_ic_state());
// Compute the actual result using the builtin for the binary operation.
State old_state = state;
state.Update(left, right, result);
- // Check if we have a string operation here.
- Handle<Code> target;
- if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
- // Setup the allocation site on-demand.
- if (allocation_site.is_null()) {
- allocation_site = isolate()->factory()->NewAllocationSite();
- }
-
- // Install the stub with an allocation site.
- BinaryOpICWithAllocationSiteStub stub(state);
- target = stub.GetCodeCopyFromTemplate(isolate(), allocation_site);
-
- // Sanity check the trampoline stub.
- ASSERT_EQ(*allocation_site, target->FindFirstAllocationSite());
- } else {
- // Install the generic stub.
- BinaryOpICStub stub(state);
- target = stub.GetCode(isolate());
-
- // Sanity check the generic stub.
- ASSERT_EQ(NULL, target->FindFirstAllocationSite());
- }
- set_target(*target);
+ // Install the new stub.
+ BinaryOpICStub stub(state);
+ set_target(*stub.GetCode(isolate()));
if (FLAG_trace_ic) {
char buffer[150];
old_state.Print(&stream);
stream.Add(" => ");
state.Print(&stream);
- stream.Add(" @ %p <- ", static_cast<void*>(*target));
+ stream.Add(" @ %p <- ", static_cast<void*>(*target()));
stream.OutputToStdOut();
JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
- if (!allocation_site.is_null()) {
- PrintF(" using allocation site %p", static_cast<void*>(*allocation_site));
- }
PrintF("]\n");
}
RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) {
HandleScope scope(isolate);
- ASSERT_EQ(2, args.length());
Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
BinaryOpIC ic(isolate);
- return ic.Transition(Handle<AllocationSite>::null(), left, right);
-}
-
-
-RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_MissWithAllocationSite) {
- HandleScope scope(isolate);
- ASSERT_EQ(3, args.length());
- Handle<AllocationSite> allocation_site = args.at<AllocationSite>(
- BinaryOpWithAllocationSiteStub::kAllocationSite);
- Handle<Object> left = args.at<Object>(
- BinaryOpWithAllocationSiteStub::kLeft);
- Handle<Object> right = args.at<Object>(
- BinaryOpWithAllocationSiteStub::kRight);
- BinaryOpIC ic(isolate);
- return ic.Transition(allocation_site, left, right);
+ return ic.Transition(left, right);
}
right_kind_ > SMI && right_kind_ <= NUMBER));
}
- // Returns true if the IC _could_ create allocation mementos.
- bool CouldCreateAllocationMementos() const {
- if (left_kind_ == STRING || right_kind_ == STRING) {
- ASSERT_EQ(Token::ADD, op_);
- return true;
- }
- return false;
- }
-
- // Returns true if the IC _should_ create allocation mementos.
- bool ShouldCreateAllocationMementos() const {
- return FLAG_allocation_site_pretenuring &&
- CouldCreateAllocationMementos();
- }
-
bool HasSideEffects() const {
return Max(left_kind_, right_kind_) == GENERIC;
}
- // Returns true if the IC should enable the inline smi code (i.e. if either
- // parameter may be a smi).
bool UseInlinedSmiCode() const {
return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
}
static Builtins::JavaScript TokenToJSBuiltin(Token::Value op);
- MaybeObject* Transition(Handle<AllocationSite> allocation_site,
- Handle<Object> left,
- Handle<Object> right) V8_WARN_UNUSED_RESULT;
+ MUST_USE_RESULT MaybeObject* Transition(Handle<Object> left,
+ Handle<Object> right);
};
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss);
-DECLARE_RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_MissWithAllocationSite);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss);
inline bool AllocationSite::CanTrack(InstanceType type) {
if (FLAG_allocation_site_pretenuring) {
- return type == JS_ARRAY_TYPE ||
- type == JS_OBJECT_TYPE ||
- type < FIRST_NONSTRING_TYPE;
+ return type == JS_ARRAY_TYPE || type == JS_OBJECT_TYPE;
}
return type == JS_ARRAY_TYPE;
}
}
-AllocationSite* Code::FindFirstAllocationSite() {
- Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
- return (result != NULL) ? AllocationSite::cast(result) : NULL;
-}
-
-
Map* Code::FindFirstMap() {
Object* result = FindNthObject(1, GetHeap()->meta_map());
return (result != NULL) ? Map::cast(result) : NULL;
"DoPushArgument not implemented for double type") \
V(kEmitLoadRegisterUnsupportedDoubleImmediate, \
"EmitLoadRegister: Unsupported double immediate") \
- V(kEval, "eval") \
+ V(kEval, "Eval") \
V(kExpected0AsASmiSentinel, "Expected 0 as a Smi sentinel") \
- V(kExpectedAlignmentMarker, "expected alignment marker") \
- V(kExpectedAllocationSite, "expected allocation site") \
+ V(kExpectedAlignmentMarker, "Expected alignment marker") \
V(kExpectedAllocationSiteInCell, \
"Expected AllocationSite in property cell") \
V(kExpectedPropertyCellInRegisterA2, \
Object* FindNthObject(int n, Map* match_map);
void ReplaceNthObject(int n, Map* match_map, Object* replace_with);
- // Find the first allocation site in an IC stub.
- AllocationSite* FindFirstAllocationSite();
-
// Find the first map in an IC stub.
Map* FindFirstMap();
void FindAllMaps(MapHandleList* maps);
Handle<Type>* right,
Handle<Type>* result,
Maybe<int>* fixed_right_arg,
- Handle<AllocationSite>* allocation_site,
Token::Value op) {
Handle<Object> object = GetInfo(id);
if (!object->IsCode()) {
op > BinaryOpIC::State::LAST_TOKEN);
*left = *right = *result = handle(Type::None(), isolate_);
*fixed_right_arg = Maybe<int>();
- *allocation_site = Handle<AllocationSite>::null();
return;
}
Handle<Code> code = Handle<Code>::cast(object);
*right = state.GetRightType(isolate());
*result = state.GetResultType(isolate());
*fixed_right_arg = state.fixed_right_arg();
-
- AllocationSite* first_allocation_site = code->FindFirstAllocationSite();
- if (first_allocation_site != NULL) {
- *allocation_site = handle(first_allocation_site);
- } else {
- *allocation_site = Handle<AllocationSite>::null();
- }
}
Handle<Type>* right,
Handle<Type>* result,
Maybe<int>* fixed_right_arg,
- Handle<AllocationSite>* allocation_site,
Token::Value operation);
void CompareType(TypeFeedbackId id,
// Collect type feedback.
Handle<Type> type, left_type, right_type;
Maybe<int> fixed_right_arg;
- Handle<AllocationSite> allocation_site;
oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
- &left_type, &right_type, &type, &fixed_right_arg,
- &allocation_site, expr->op());
+ &left_type, &right_type, &type, &fixed_right_arg, expr->op());
NarrowLowerType(expr, type);
NarrowLowerType(expr->left(), left_type);
NarrowLowerType(expr->right(), right_type);
- expr->set_allocation_site(allocation_site);
expr->set_fixed_right_arg(fixed_right_arg);
if (expr->op() == Token::OR || expr->op() == Token::AND) {
expr->left()->RecordToBooleanTypeFeedback(oracle());
}
+void BinaryOpICStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { rdx, rax };
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
+ descriptor->SetMissHandler(
+ ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
+}
+
+
static void InitializeArrayConstructorDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor,
}
-void BinaryOpICStub::InitializeInterfaceDescriptor(
- Isolate* isolate,
- CodeStubInterfaceDescriptor* descriptor) {
- static Register registers[] = { rdx, rax };
- descriptor->register_param_count_ = 2;
- descriptor->register_params_ = registers;
- descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
- descriptor->SetMissHandler(
- ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
-}
-
-
-void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
- Isolate* isolate,
- CodeStubInterfaceDescriptor* descriptor) {
- static Register registers[] = { rcx, rdx, rax };
- descriptor->register_param_count_ = 3;
- descriptor->register_params_ = registers;
- descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
-}
-
-
void NewStringAddStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
- BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
}
}
-void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rdx : left
- // -- rax : right
- // -- rsp[0] : return address
- // -----------------------------------
- Isolate* isolate = masm->isolate();
-
- // Load rcx with the allocation site. We stick an undefined dummy value here
- // and replace it with the real allocation site later when we instantiate this
- // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
- __ Move(rcx, handle(isolate->heap()->undefined_value()));
-
- // Make sure that we actually patched the allocation site.
- if (FLAG_debug_code) {
- __ testb(rcx, Immediate(kSmiTagMask));
- __ Assert(zero, kExpectedAllocationSite);
- __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
- isolate->factory()->allocation_site_map());
- __ Assert(equal, kExpectedAllocationSite);
- }
-
- // Tail call into the stub that handles binary operations with allocation
- // sites.
- BinaryOpWithAllocationSiteStub stub(state_);
- __ TailCallStub(&stub);
-}
-
-
void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
ASSERT(state_ == CompareIC::SMI);
Label miss;