Index: src/code-stubs-hydrogen.cc |
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc |
index 9f9b14e309d975f15c77020d72a6e38b8e3e0a28..43cf265e97f94af41800587d3ac5831674df74f1 100644 |
--- a/src/code-stubs-hydrogen.cc |
+++ b/src/code-stubs-hydrogen.cc |
@@ -113,6 +113,8 @@ class CodeStubGraphBuilderBase : public HGraphBuilder { |
HValue* shared_info, |
HValue* native_context); |
+ HValue* CheckString(HValue* input, bool convert); |
+ |
private: |
HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder); |
HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder, |
@@ -1456,6 +1458,66 @@ Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode() { |
} |
+HValue* CodeStubGraphBuilderBase::CheckString(HValue* input, bool convert) { |
+ if (!convert) return BuildCheckString(input); |
+ IfBuilder if_inputissmi(this); |
+ HValue* inputissmi = if_inputissmi.If<HIsSmiAndBranch>(input); |
+ if_inputissmi.Then(); |
+ { |
+ // Convert the input smi to a string. |
+ Push(BuildNumberToString(input, Type::SignedSmall())); |
+ } |
+ if_inputissmi.Else(); |
+ { |
+ HValue* input_map = |
+ Add<HLoadNamedField>(input, inputissmi, HObjectAccess::ForMap()); |
+ HValue* input_instance_type = Add<HLoadNamedField>( |
+ input_map, inputissmi, HObjectAccess::ForMapInstanceType()); |
+ IfBuilder if_inputisstring(this); |
+ if_inputisstring.If<HCompareNumericAndBranch>( |
+ input_instance_type, Add<HConstant>(FIRST_NONSTRING_TYPE), Token::LT); |
+ if_inputisstring.Then(); |
+ { |
+ // The input is already a string. |
+ Push(input); |
+ } |
+ if_inputisstring.Else(); |
+ { |
+ // Convert to primitive first (if necessary), see |
+ // ES6 section 12.7.3 The Addition operator. |
+ IfBuilder if_inputisprimitive(this); |
+ STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); |
+ if_inputisprimitive.If<HCompareNumericAndBranch>( |
+ input_instance_type, Add<HConstant>(LAST_PRIMITIVE_TYPE), Token::LTE); |
+ if_inputisprimitive.Then(); |
+ { |
+ // The input is already a primitive. |
+ Push(input); |
+ } |
+ if_inputisprimitive.Else(); |
+ { |
+ // TODO(bmeurer): Add support for fast ToPrimitive conversion using |
+ // a dedicated ToPrimitiveStub. |
+ Add<HPushArguments>(input); |
+ Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kToPrimitive), |
+ 1)); |
+ } |
+ if_inputisprimitive.End(); |
+ // Convert the primitive to a string value. |
+ ToStringDescriptor descriptor(isolate()); |
+ ToStringStub stub(isolate()); |
+ HValue* values[] = {context(), Pop()}; |
+ Push(AddUncasted<HCallWithDescriptor>( |
+ Add<HConstant>(stub.GetCode()), 0, descriptor, |
+ Vector<HValue*>(values, arraysize(values)))); |
+ } |
+ if_inputisstring.End(); |
+ } |
+ if_inputissmi.End(); |
+ return Pop(); |
+} |
+ |
+ |
template <> |
HValue* CodeStubGraphBuilder<StringAddStub>::BuildCodeInitializedStub() { |
StringAddStub* stub = casted_stub(); |
@@ -1467,10 +1529,12 @@ HValue* CodeStubGraphBuilder<StringAddStub>::BuildCodeInitializedStub() { |
// Make sure that both arguments are strings if not known in advance. |
if ((flags & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { |
- left = BuildCheckString(left); |
+ left = |
+ CheckString(left, (flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT); |
} |
if ((flags & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { |
- right = BuildCheckString(right); |
+ right = |
+ CheckString(right, (flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT); |
} |
return BuildStringAdd(left, right, HAllocationMode(pretenure_flag)); |