aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/code-stubs-hydrogen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/code-stubs-hydrogen.cc')
-rw-r--r--deps/v8/src/code-stubs-hydrogen.cc205
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),