diff options
Diffstat (limited to 'deps/v8/src/code-stubs-hydrogen.cc')
-rw-r--r-- | deps/v8/src/code-stubs-hydrogen.cc | 205 |
1 files changed, 175 insertions, 30 deletions
diff --git a/deps/v8/src/code-stubs-hydrogen.cc b/deps/v8/src/code-stubs-hydrogen.cc index 81304e5002..dc2ae554bf 100644 --- a/deps/v8/src/code-stubs-hydrogen.cc +++ b/deps/v8/src/code-stubs-hydrogen.cc @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/v8.h" +#include "src/code-stubs.h" #include "src/bailout-reason.h" -#include "src/code-stubs.h" #include "src/field-index.h" #include "src/hydrogen.h" #include "src/ic/ic.h" @@ -114,6 +113,9 @@ class CodeStubGraphBuilderBase : public HGraphBuilder { HValue* shared_info, HValue* native_context); + HValue* BuildToString(HValue* input, bool convert); + HValue* BuildToPrimitive(HValue* input, HValue* input_map); + private: HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder); HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder, @@ -132,7 +134,7 @@ bool CodeStubGraphBuilderBase::BuildGraph() { isolate()->counters()->code_stubs()->Increment(); if (FLAG_trace_hydrogen_stubs) { - const char* name = CodeStub::MajorName(stub()->MajorKey(), false); + const char* name = CodeStub::MajorName(stub()->MajorKey()); PrintF("-----------------------------------------------------------\n"); PrintF("Compiling stub %s using hydrogen\n", name); isolate()->GetHTracer()->TraceCompilation(info()); @@ -156,8 +158,8 @@ bool CodeStubGraphBuilderBase::BuildGraph() { HParameter::STACK_PARAMETER, r); } else { param = Add<HParameter>(i, HParameter::REGISTER_PARAMETER, r); + start_environment->Bind(i, param); } - start_environment->Bind(i, param); parameters_[i] = param; if (i < register_param_count && IsParameterCountRegister(i)) { param->set_type(HType::Smi()); @@ -368,14 +370,16 @@ HValue* CodeStubGraphBuilder<TypeofStub>::BuildCodeStub() { { Push(Add<HConstant>(factory->symbol_string())); } is_symbol.Else(); { + HValue* bit_field = Add<HLoadNamedField>( + map, nullptr, HObjectAccess::ForMapBitField()); + HValue* bit_field_masked = AddUncasted<HBitwise>( + Token::BIT_AND, bit_field, + Add<HConstant>((1 << Map::kIsCallable) | + (1 << Map::kIsUndetectable))); IfBuilder is_function(this); - HConstant* js_function = Add<HConstant>(JS_FUNCTION_TYPE); - HConstant* js_function_proxy = - Add<HConstant>(JS_FUNCTION_PROXY_TYPE); - is_function.If<HCompareNumericAndBranch>(instance_type, js_function, - Token::EQ); - is_function.OrIf<HCompareNumericAndBranch>( - instance_type, js_function_proxy, Token::EQ); + is_function.If<HCompareNumericAndBranch>( + bit_field_masked, Add<HConstant>(1 << Map::kIsCallable), + Token::EQ); is_function.Then(); { Push(Add<HConstant>(factory->function_string())); } is_function.Else(); @@ -391,7 +395,9 @@ HValue* CodeStubGraphBuilder<TypeofStub>::BuildCodeStub() { #undef SIMD128_BUILDER_OPEN // Is it an undetectable object? IfBuilder is_undetectable(this); - is_undetectable.If<HIsUndetectableAndBranch>(object); + is_undetectable.If<HCompareNumericAndBranch>( + bit_field_masked, Add<HConstant>(1 << Map::kIsUndetectable), + Token::EQ); is_undetectable.Then(); { // typeof an undetectable object is 'undefined'. @@ -436,8 +442,9 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() { // so that it doesn't build and eager frame. info()->MarkMustNotHaveEagerFrame(); - HInstruction* allocation_site = - Add<HLoadKeyed>(GetParameter(0), GetParameter(1), nullptr, FAST_ELEMENTS); + HInstruction* allocation_site = Add<HLoadKeyed>( + GetParameter(0), GetParameter(1), nullptr, FAST_ELEMENTS, + NEVER_RETURN_HOLE, LiteralsArray::kOffsetToFirstLiteral - kHeapObjectTag); IfBuilder checker(this); checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, undefined); @@ -498,8 +505,9 @@ template <> HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() { HValue* undefined = graph()->GetConstantUndefined(); - HInstruction* allocation_site = - Add<HLoadKeyed>(GetParameter(0), GetParameter(1), nullptr, FAST_ELEMENTS); + HInstruction* allocation_site = Add<HLoadKeyed>( + GetParameter(0), GetParameter(1), nullptr, FAST_ELEMENTS, + NEVER_RETURN_HOLE, LiteralsArray::kOffsetToFirstLiteral - kHeapObjectTag); IfBuilder checker(this); checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, @@ -1016,7 +1024,7 @@ Handle<Code> StoreFieldStub::GenerateCode() { return DoGenerateCode(this); } template <> HValue* CodeStubGraphBuilder<StoreTransitionStub>::BuildCodeStub() { - HValue* object = GetParameter(StoreTransitionDescriptor::kReceiverIndex); + HValue* object = GetParameter(StoreTransitionHelper::ReceiverIndex()); switch (casted_stub()->store_mode()) { case StoreTransitionStub::ExtendStorageAndStoreMapAndValue: { @@ -1047,17 +1055,17 @@ HValue* CodeStubGraphBuilder<StoreTransitionStub>::BuildCodeStub() { case StoreTransitionStub::StoreMapAndValue: // Store the new value into the "extended" object. BuildStoreNamedField( - object, GetParameter(StoreTransitionDescriptor::kValueIndex), + object, GetParameter(StoreTransitionHelper::ValueIndex()), casted_stub()->index(), casted_stub()->representation(), true); // Fall through. case StoreTransitionStub::StoreMapOnly: // And finally update the map. Add<HStoreNamedField>(object, HObjectAccess::ForMap(), - GetParameter(StoreTransitionDescriptor::kMapIndex)); + GetParameter(StoreTransitionHelper::MapIndex())); break; } - return GetParameter(StoreTransitionDescriptor::kValueIndex); + return GetParameter(StoreTransitionHelper::ValueIndex()); } @@ -1453,6 +1461,140 @@ Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode() { } +HValue* CodeStubGraphBuilderBase::BuildToString(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(); + { + // Convert the input to a primitive. + Push(BuildToPrimitive(input, input_map)); + } + 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(); +} + + +HValue* CodeStubGraphBuilderBase::BuildToPrimitive(HValue* input, + HValue* input_map) { + // Get the native context of the caller. + HValue* native_context = BuildGetNativeContext(); + + // Determine the initial map of the %ObjectPrototype%. + HValue* object_function_prototype_map = + Add<HLoadNamedField>(native_context, nullptr, + HObjectAccess::ForContextSlot( + Context::OBJECT_FUNCTION_PROTOTYPE_MAP_INDEX)); + + // Determine the initial map of the %StringPrototype%. + HValue* string_function_prototype_map = + Add<HLoadNamedField>(native_context, nullptr, + HObjectAccess::ForContextSlot( + Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); + + // Determine the initial map of the String function. + HValue* string_function = Add<HLoadNamedField>( + native_context, nullptr, + HObjectAccess::ForContextSlot(Context::STRING_FUNCTION_INDEX)); + HValue* string_function_initial_map = Add<HLoadNamedField>( + string_function, nullptr, HObjectAccess::ForPrototypeOrInitialMap()); + + // Determine the map of the [[Prototype]] of {input}. + HValue* input_prototype = + Add<HLoadNamedField>(input_map, nullptr, HObjectAccess::ForPrototype()); + HValue* input_prototype_map = + Add<HLoadNamedField>(input_prototype, nullptr, HObjectAccess::ForMap()); + + // For string wrappers (JSValue instances with [[StringData]] internal + // fields), we can shortcirciut the ToPrimitive if + // + // (a) the {input} map matches the initial map of the String function, + // (b) the {input} [[Prototype]] is the unmodified %StringPrototype% (i.e. + // no one monkey-patched toString, @@toPrimitive or valueOf), and + // (c) the %ObjectPrototype% (i.e. the [[Prototype]] of the + // %StringPrototype%) is also unmodified, that is no one sneaked a + // @@toPrimitive into the %ObjectPrototype%. + // + // If all these assumptions hold, we can just take the [[StringData]] value + // and return it. + // TODO(bmeurer): This just repairs a regression introduced by removing the + // weird (and broken) intrinsic %_IsStringWrapperSafeForDefaultValue, which + // was intendend to something similar to this, although less efficient and + // wrong in the presence of @@toPrimitive. Long-term we might want to move + // into the direction of having a ToPrimitiveStub that can do common cases + // while staying in JavaScript land (i.e. not going to C++). + IfBuilder if_inputisstringwrapper(this); + if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( + input_map, string_function_initial_map); + if_inputisstringwrapper.And(); + if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( + input_prototype_map, string_function_prototype_map); + if_inputisstringwrapper.And(); + if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( + Add<HLoadNamedField>(Add<HLoadNamedField>(input_prototype_map, nullptr, + HObjectAccess::ForPrototype()), + nullptr, HObjectAccess::ForMap()), + object_function_prototype_map); + if_inputisstringwrapper.Then(); + { + Push(BuildLoadNamedField( + input, FieldIndex::ForInObjectOffset(JSValue::kValueOffset))); + } + if_inputisstringwrapper.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_inputisstringwrapper.End(); + return Pop(); +} + + template <> HValue* CodeStubGraphBuilder<StringAddStub>::BuildCodeInitializedStub() { StringAddStub* stub = casted_stub(); @@ -1464,10 +1606,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 = + BuildToString(left, (flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT); } if ((flags & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { - right = BuildCheckString(right); + right = BuildToString(right, + (flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT); } return BuildStringAdd(left, right, HAllocationMode(pretenure_flag)); @@ -1610,10 +1754,10 @@ Handle<Code> StoreGlobalStub::GenerateCode() { template <> HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() { - HValue* object = GetParameter(StoreTransitionDescriptor::kReceiverIndex); - HValue* key = GetParameter(StoreTransitionDescriptor::kNameIndex); - HValue* value = GetParameter(StoreTransitionDescriptor::kValueIndex); - HValue* map = GetParameter(StoreTransitionDescriptor::kMapIndex); + HValue* object = GetParameter(StoreTransitionHelper::ReceiverIndex()); + HValue* key = GetParameter(StoreTransitionHelper::NameIndex()); + HValue* value = GetParameter(StoreTransitionHelper::ValueIndex()); + HValue* map = GetParameter(StoreTransitionHelper::MapIndex()); if (FLAG_trace_elements_transitions) { // Tracing elements transitions is the job of the runtime. @@ -1664,13 +1808,15 @@ void CodeStubGraphBuilderBase::BuildCheckAndInstallOptimizedCode( optimized_map, map_index, SharedFunctionInfo::kContextOffset); HValue* osr_ast_slot = LoadFromOptimizedCodeMap( optimized_map, map_index, SharedFunctionInfo::kOsrAstIdOffset); + HValue* code_object = LoadFromOptimizedCodeMap( + optimized_map, map_index, SharedFunctionInfo::kCachedCodeOffset); builder->If<HCompareObjectEqAndBranch>(native_context, context_slot); builder->AndIf<HCompareObjectEqAndBranch>(osr_ast_slot, osr_ast_id_none); + builder->And(); + builder->IfNot<HCompareObjectEqAndBranch>(code_object, + graph()->GetConstantUndefined()); builder->Then(); - HValue* code_object = LoadFromOptimizedCodeMap(optimized_map, - map_index, SharedFunctionInfo::kCachedCodeOffset); - // and the literals HValue* literals = LoadFromOptimizedCodeMap(optimized_map, map_index, SharedFunctionInfo::kLiteralsOffset); @@ -2192,7 +2338,6 @@ HValue* CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildCodeStub() { // KeyedLookupCache miss; call runtime. Add<HPushArguments>(receiver, key); Push(Add<HCallRuntime>( - isolate()->factory()->empty_string(), Runtime::FunctionForId(is_strong(casted_stub()->language_mode()) ? Runtime::kKeyedGetPropertyStrong : Runtime::kKeyedGetProperty), |