Revert "Fix compilation with C++11." and "Allocation site support for monomorphic StringAdds in BinaryOps.".
This reverts commit r18431 and r18432 for breaking the Linux nosnapshot build. R=ulan@chromium.org Review URL: https://codereview.chromium.org/122463004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18434 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e785e60bea
commit
4d88b0b4be
@ -193,6 +193,18 @@ void CompareNilICStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
@ -327,29 +339,6 @@ void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
@ -1453,7 +1442,6 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
|
||||
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
|
||||
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
|
||||
BinaryOpICStub::GenerateAheadOfTime(isolate);
|
||||
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
|
||||
}
|
||||
|
||||
|
||||
@ -4174,38 +4162,6 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -1936,10 +1936,6 @@ class BinaryOperation V8_FINAL : public Expression {
|
||||
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_; }
|
||||
|
||||
@ -1968,7 +1964,6 @@ class BinaryOperation V8_FINAL : public Expression {
|
||||
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.
|
||||
|
@ -911,7 +911,6 @@ HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
|
||||
(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())) {
|
||||
@ -925,15 +924,14 @@ HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
|
||||
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();
|
||||
@ -945,15 +943,14 @@ HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
|
||||
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();
|
||||
@ -962,7 +959,7 @@ HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
|
||||
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
|
||||
@ -1009,31 +1006,6 @@ Handle<Code> BinaryOpICStub::GenerateCode(Isolate* isolate) {
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
@ -1051,7 +1023,7 @@ HValue* CodeStubGraphBuilder<NewStringAddStub>::BuildCodeInitializedStub() {
|
||||
right = BuildCheckString(right);
|
||||
}
|
||||
|
||||
return BuildStringAdd(left, right, HAllocationMode(pretenure_flag));
|
||||
return BuildStringAdd(left, right, pretenure_flag);
|
||||
}
|
||||
|
||||
|
||||
|
@ -247,28 +247,6 @@ void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
|
||||
}
|
||||
|
||||
|
||||
// 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) {
|
||||
|
107
src/code-stubs.h
107
src/code-stubs.h
@ -42,8 +42,6 @@ namespace internal {
|
||||
V(CallFunction) \
|
||||
V(CallConstruct) \
|
||||
V(BinaryOpIC) \
|
||||
V(BinaryOpICWithAllocationSite) \
|
||||
V(BinaryOpWithAllocationSite) \
|
||||
V(StringAdd) \
|
||||
V(NewStringAdd) \
|
||||
V(SubString) \
|
||||
@ -1064,7 +1062,7 @@ class KeyedArrayCallStub: public HICStub {
|
||||
};
|
||||
|
||||
|
||||
class BinaryOpICStub : public HydrogenCodeStub {
|
||||
class BinaryOpICStub V8_FINAL : public HydrogenCodeStub {
|
||||
public:
|
||||
BinaryOpICStub(Token::Value op, OverwriteMode mode)
|
||||
: HydrogenCodeStub(UNINITIALIZED), state_(op, mode) {}
|
||||
@ -1082,64 +1080,6 @@ class BinaryOpICStub : public HydrogenCodeStub {
|
||||
return Code::BINARY_OP_IC;
|
||||
}
|
||||
|
||||
virtual InlineCacheState GetICState() V8_FINAL V8_OVERRIDE {
|
||||
return state_.GetICState();
|
||||
}
|
||||
|
||||
virtual ExtraICState GetExtraICState() V8_FINAL V8_OVERRIDE {
|
||||
return state_.GetExtraICState();
|
||||
}
|
||||
|
||||
virtual void VerifyPlatformFeatures(Isolate* isolate) V8_FINAL V8_OVERRIDE {
|
||||
ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
|
||||
}
|
||||
|
||||
virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// Parameters accessed via CodeStubGraphBuilder::GetParameter()
|
||||
static const int kLeft = 0;
|
||||
static const int kRight = 1;
|
||||
|
||||
private:
|
||||
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();
|
||||
}
|
||||
@ -1152,47 +1092,26 @@ class BinaryOpICWithAllocationSiteStub V8_FINAL : public PlatformCodeStub {
|
||||
ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
|
||||
}
|
||||
|
||||
virtual void Generate(MacroAssembler* masm) V8_OVERRIDE;
|
||||
virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
|
||||
|
||||
const BinaryOpIC::State& state() const { return state_; }
|
||||
|
||||
virtual void PrintState(StringStream* stream) V8_OVERRIDE;
|
||||
|
||||
virtual Major MajorKey() V8_OVERRIDE { return BinaryOpICWithAllocationSite; }
|
||||
virtual int MinorKey() V8_OVERRIDE { return GetExtraICState(); }
|
||||
// Parameters accessed via CodeStubGraphBuilder::GetParameter()
|
||||
static const int kLeft = 0;
|
||||
static const int kRight = 1;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
@ -1211,10 +1130,6 @@ class NewStringAddStub V8_FINAL : public HydrogenCodeStub {
|
||||
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(
|
||||
|
@ -3815,9 +3815,7 @@ HInstruction* HStringAdd::New(Zone* zone,
|
||||
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);
|
||||
@ -3827,23 +3825,7 @@ HInstruction* HStringAdd::New(Zone* zone,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6992,55 +6992,45 @@ class HStringAdd V8_FINAL : public HBinaryOperation {
|
||||
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_;
|
||||
};
|
||||
|
||||
|
||||
|
539
src/hydrogen.cc
539
src/hydrogen.cc
@ -1693,131 +1693,22 @@ HValue* HGraphBuilder::BuildNumberToString(HValue* object,
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -1843,54 +1734,123 @@ void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
@ -1909,12 +1869,7 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(
|
||||
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>(
|
||||
@ -1924,84 +1879,90 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(
|
||||
graph()->GetConstant0(), Token::NE);
|
||||
if_onebyte.Then();
|
||||
{
|
||||
// Allocate sequential one-byte string object.
|
||||
Push(length);
|
||||
Push(ascii_string_map);
|
||||
// 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::ONE_BYTE_ENCODING,
|
||||
string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
||||
left_length);
|
||||
|
||||
// Copy bytes from the right string.
|
||||
BuildCopySeqStringChars(
|
||||
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_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.
|
||||
HValue* size = BuildSeqStringSizeFor(
|
||||
length, String::TWO_BYTE_ENCODING);
|
||||
|
||||
// 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 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);
|
||||
|
||||
// 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.
|
||||
AddStoreMapConstantNoWriteBarrier(string, map);
|
||||
|
||||
// We can safely skip the write barrier for storing map here.
|
||||
AddStoreMapNoWriteBarrier(result, map);
|
||||
// Length must be stored into the string before we copy characters to
|
||||
// make debug verification code happy.
|
||||
Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
|
||||
length);
|
||||
|
||||
// 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.
|
||||
// Copy bytes from the left string.
|
||||
BuildCopySeqStringChars(
|
||||
left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
|
||||
result, 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::TWO_BYTE_ENCODING,
|
||||
result, left_length, String::TWO_BYTE_ENCODING,
|
||||
string, left_length, String::TWO_BYTE_ENCODING,
|
||||
right_length);
|
||||
}
|
||||
if_twobyte.Else();
|
||||
{
|
||||
// Copy characters from the left string.
|
||||
BuildCopySeqStringChars(
|
||||
left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
||||
result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
||||
left_length);
|
||||
|
||||
// Copy characters from the right string.
|
||||
BuildCopySeqStringChars(
|
||||
right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
||||
result, left_length, String::ONE_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();
|
||||
{
|
||||
@ -2020,21 +1981,20 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
@ -2042,13 +2002,13 @@ HValue* HGraphBuilder::BuildStringAdd(
|
||||
// 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());
|
||||
@ -2056,14 +2016,14 @@ HValue* HGraphBuilder::BuildStringAdd(
|
||||
// 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();
|
||||
}
|
||||
@ -6140,27 +6100,15 @@ HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object,
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
@ -8608,9 +8556,13 @@ HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -8741,18 +8693,10 @@ HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
|
||||
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.
|
||||
@ -8772,8 +8716,7 @@ HValue* HGraphBuilder::BuildBinaryOperation(
|
||||
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);
|
||||
@ -8839,48 +8782,7 @@ HValue* HGraphBuilder::BuildBinaryOperation(
|
||||
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()) {
|
||||
@ -10109,7 +10011,8 @@ void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -995,35 +995,6 @@ class HIfContinuation V8_FINAL {
|
||||
};
|
||||
|
||||
|
||||
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)
|
||||
@ -1320,18 +1291,9 @@ class HGraphBuilder {
|
||||
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,
|
||||
@ -1343,11 +1305,11 @@ class HGraphBuilder {
|
||||
// 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,
|
||||
@ -1370,14 +1332,7 @@ class HGraphBuilder {
|
||||
|
||||
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) {
|
||||
@ -1398,8 +1353,7 @@ class HGraphBuilder {
|
||||
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);
|
||||
|
||||
|
@ -342,17 +342,6 @@ void BinaryOpICStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
@ -2663,10 +2652,8 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
|
||||
if (Serializer::enabled()) {
|
||||
PlatformFeatureScope sse2(SSE2);
|
||||
BinaryOpICStub::GenerateAheadOfTime(isolate);
|
||||
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
|
||||
} else {
|
||||
BinaryOpICStub::GenerateAheadOfTime(isolate);
|
||||
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4398,35 +4385,6 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -4912,7 +4912,7 @@ void LCodeGen::DoStringAdd(LStringAdd* instr) {
|
||||
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());
|
||||
|
70
src/ic.cc
70
src/ic.cc
@ -2398,11 +2398,6 @@ void BinaryOpIC::State::GenerateAheadOfTime(
|
||||
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);
|
||||
@ -2602,7 +2597,6 @@ void BinaryOpIC::State::Print(StringStream* stream) const {
|
||||
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);
|
||||
@ -2642,18 +2636,6 @@ void BinaryOpIC::State::Update(Handle<Object> left,
|
||||
}
|
||||
}
|
||||
|
||||
// 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) ||
|
||||
@ -2739,9 +2721,7 @@ Handle<Type> BinaryOpIC::State::KindToType(Kind kind, Isolate* isolate) {
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
@ -2757,29 +2737,9 @@ MaybeObject* BinaryOpIC::Transition(Handle<AllocationSite> allocation_site,
|
||||
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];
|
||||
@ -2790,12 +2750,9 @@ MaybeObject* BinaryOpIC::Transition(Handle<AllocationSite> allocation_site,
|
||||
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");
|
||||
}
|
||||
|
||||
@ -2812,25 +2769,10 @@ MaybeObject* BinaryOpIC::Transition(Handle<AllocationSite> allocation_site,
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
23
src/ic.h
23
src/ic.h
@ -861,27 +861,10 @@ class BinaryOpIC: public IC {
|
||||
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_);
|
||||
}
|
||||
@ -943,9 +926,8 @@ class BinaryOpIC: public IC {
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
@ -1054,7 +1036,6 @@ DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure);
|
||||
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);
|
||||
|
||||
|
@ -1349,9 +1349,7 @@ AllocationSiteMode AllocationSite::GetMode(ElementsKind from,
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -10477,12 +10477,6 @@ Object* Code::FindNthObject(int n, Map* match_map) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -1104,10 +1104,9 @@ class MaybeObject BASE_EMBEDDED {
|
||||
"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, \
|
||||
@ -5248,9 +5247,6 @@ class Code: public HeapObject {
|
||||
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);
|
||||
|
@ -283,7 +283,6 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
|
||||
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()) {
|
||||
@ -293,7 +292,6 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
|
||||
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);
|
||||
@ -305,13 +303,6 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
|
||||
*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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,7 +112,6 @@ class TypeFeedbackOracle: public ZoneObject {
|
||||
Handle<Type>* right,
|
||||
Handle<Type>* result,
|
||||
Maybe<int>* fixed_right_arg,
|
||||
Handle<AllocationSite>* allocation_site,
|
||||
Token::Value operation);
|
||||
|
||||
void CompareType(TypeFeedbackId id,
|
||||
|
@ -629,14 +629,11 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
// 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());
|
||||
|
@ -180,6 +180,18 @@ void TransitionElementsKindStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
@ -327,29 +339,6 @@ void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
@ -2494,7 +2483,6 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
|
||||
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
|
||||
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
|
||||
BinaryOpICStub::GenerateAheadOfTime(isolate);
|
||||
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
|
||||
}
|
||||
|
||||
|
||||
@ -4241,35 +4229,6 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user