Revert "Revert "Upgrade to 5.0.71.48"" DO NOT MERGE
This reverts commit f2e3994fa5148cc3d9946666f0b0596290192b0e,
and updates the x64 makefile properly so it doesn't break that
build.
FPIIM-449
Change-Id: Ib83e35bfbae6af627451c926a9650ec57c045605
(cherry picked from commit 109988c7ccb6f3fd1a58574fa3dfb88beaef6632)
diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc
index 98337be..b6fdd3a 100644
--- a/src/crankshaft/hydrogen.cc
+++ b/src/crankshaft/hydrogen.cc
@@ -34,6 +34,7 @@
#include "src/crankshaft/hydrogen-uint32-analysis.h"
#include "src/crankshaft/lithium-allocator.h"
#include "src/crankshaft/typing.h"
+#include "src/field-type.h"
#include "src/full-codegen/full-codegen.h"
#include "src/ic/call-optimization.h"
#include "src/ic/ic.h"
@@ -687,33 +688,28 @@
return value ? GetConstantTrue() : GetConstantFalse();
}
+#define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value, \
+ undetectable) \
+ HConstant* HGraph::GetConstant##Name() { \
+ if (!constant_##name##_.is_set()) { \
+ HConstant* constant = new (zone()) HConstant( \
+ Unique<Object>::CreateImmovable( \
+ isolate()->factory()->name##_value()), \
+ Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \
+ false, Representation::Tagged(), htype, true, boolean_value, \
+ undetectable, ODDBALL_TYPE); \
+ constant->InsertAfter(entry_block()->first()); \
+ constant_##name##_.set(constant); \
+ } \
+ return ReinsertConstantIfNecessary(constant_##name##_.get()); \
+ }
-#define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value) \
-HConstant* HGraph::GetConstant##Name() { \
- if (!constant_##name##_.is_set()) { \
- HConstant* constant = new(zone()) HConstant( \
- Unique<Object>::CreateImmovable(isolate()->factory()->name##_value()), \
- Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \
- false, \
- Representation::Tagged(), \
- htype, \
- true, \
- boolean_value, \
- false, \
- ODDBALL_TYPE); \
- constant->InsertAfter(entry_block()->first()); \
- constant_##name##_.set(constant); \
- } \
- return ReinsertConstantIfNecessary(constant_##name##_.get()); \
-}
-
-
-DEFINE_GET_CONSTANT(Undefined, undefined, undefined, HType::Undefined(), false)
-DEFINE_GET_CONSTANT(True, true, boolean, HType::Boolean(), true)
-DEFINE_GET_CONSTANT(False, false, boolean, HType::Boolean(), false)
-DEFINE_GET_CONSTANT(Hole, the_hole, the_hole, HType::None(), false)
-DEFINE_GET_CONSTANT(Null, null, null, HType::Null(), false)
-
+DEFINE_GET_CONSTANT(Undefined, undefined, undefined, HType::Undefined(), false,
+ true)
+DEFINE_GET_CONSTANT(True, true, boolean, HType::Boolean(), true, false)
+DEFINE_GET_CONSTANT(False, false, boolean, HType::Boolean(), false, false)
+DEFINE_GET_CONSTANT(Hole, the_hole, the_hole, HType::None(), false, false)
+DEFINE_GET_CONSTANT(Null, null, null, HType::Null(), false, true)
#undef DEFINE_GET_CONSTANT
@@ -1185,7 +1181,7 @@
HGraph* HGraphBuilder::CreateGraph() {
- graph_ = new(zone()) HGraph(info_);
+ graph_ = new (zone()) HGraph(info_, descriptor_);
if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_);
CompilationPhase phase("H_Block building", info_);
set_current_block(graph()->entry_block());
@@ -1275,6 +1271,14 @@
}
+HValue* HGraphBuilder::BuildEnumLength(HValue* map) {
+ NoObservableSideEffectsScope scope(this);
+ HValue* bit_field3 =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3());
+ return BuildDecodeField<Map::EnumLengthBits>(bit_field3);
+}
+
+
HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
if (obj->type().IsHeapObject()) return obj;
return Add<HCheckHeapObject>(obj);
@@ -1671,10 +1675,10 @@
return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
}
-
-HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(
- HValue* receiver, HValue* elements, HValue* key, HValue* hash,
- LanguageMode language_mode) {
+HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
+ HValue* elements,
+ HValue* key,
+ HValue* hash) {
HValue* capacity =
Add<HLoadKeyed>(elements, Add<HConstant>(NameDictionary::kCapacityIndex),
nullptr, nullptr, FAST_ELEMENTS);
@@ -1717,11 +1721,8 @@
// element == undefined means "not found". Call the runtime.
// TODO(jkummerow): walk the prototype chain instead.
Add<HPushArguments>(receiver, key);
- Push(Add<HCallRuntime>(
- Runtime::FunctionForId(is_strong(language_mode)
- ? Runtime::kKeyedGetPropertyStrong
- : Runtime::kKeyedGetProperty),
- 2));
+ Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kKeyedGetProperty),
+ 2));
}
if_undefined.Else();
{
@@ -1780,11 +1781,8 @@
FAST_ELEMENTS));
details_compare.Else();
Add<HPushArguments>(receiver, key);
- Push(Add<HCallRuntime>(
- Runtime::FunctionForId(is_strong(language_mode)
- ? Runtime::kKeyedGetPropertyStrong
- : Runtime::kKeyedGetProperty),
- 2));
+ Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kKeyedGetProperty),
+ 2));
details_compare.End();
found_key_match.Else();
@@ -1819,7 +1817,7 @@
// Allocate the JSIteratorResult object.
HValue* result =
Add<HAllocate>(Add<HConstant>(JSIteratorResult::kSize), HType::JSObject(),
- NOT_TENURED, JS_ITERATOR_RESULT_TYPE);
+ NOT_TENURED, JS_OBJECT_TYPE);
// Initialize the JSIteratorResult object.
HValue* native_context = BuildGetNativeContext();
@@ -2052,6 +2050,20 @@
return Pop();
}
+HValue* HGraphBuilder::BuildToNumber(HValue* input) {
+ if (input->type().IsTaggedNumber()) {
+ return input;
+ }
+ Callable callable = CodeFactory::ToNumber(isolate());
+ HValue* stub = Add<HConstant>(callable.code());
+ HValue* values[] = {context(), input};
+ HCallWithDescriptor* instr =
+ Add<HCallWithDescriptor>(stub, 0, callable.descriptor(),
+ Vector<HValue*>(values, arraysize(values)));
+ instr->set_type(HType::TaggedNumber());
+ return instr;
+}
+
HValue* HGraphBuilder::BuildToObject(HValue* receiver) {
NoObservableSideEffectsScope scope(this);
@@ -2578,8 +2590,8 @@
HObjectAccess::ForFixedTypedArrayBaseExternalPointer());
HValue* base_pointer = Add<HLoadNamedField>(
elements, nullptr, HObjectAccess::ForFixedTypedArrayBaseBasePointer());
- HValue* backing_store = AddUncasted<HAdd>(
- external_pointer, base_pointer, Strength::WEAK, AddOfExternalAndTagged);
+ HValue* backing_store = AddUncasted<HAdd>(external_pointer, base_pointer,
+ AddOfExternalAndTagged);
if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
NoObservableSideEffectsScope no_effects(this);
@@ -3171,37 +3183,24 @@
HIfContinuation* continuation,
MapEmbedding map_embedding) {
IfBuilder if_nil(this);
- bool some_case_handled = false;
- bool some_case_missing = false;
-
- if (type->Maybe(Type::Null())) {
- if (some_case_handled) if_nil.Or();
- if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
- some_case_handled = true;
- } else {
- some_case_missing = true;
- }
-
- if (type->Maybe(Type::Undefined())) {
- if (some_case_handled) if_nil.Or();
- if_nil.If<HCompareObjectEqAndBranch>(value,
- graph()->GetConstantUndefined());
- some_case_handled = true;
- } else {
- some_case_missing = true;
- }
if (type->Maybe(Type::Undetectable())) {
- if (some_case_handled) if_nil.Or();
if_nil.If<HIsUndetectableAndBranch>(value);
- some_case_handled = true;
} else {
- some_case_missing = true;
- }
+ bool maybe_null = type->Maybe(Type::Null());
+ if (maybe_null) {
+ if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
+ }
- if (some_case_missing) {
+ if (type->Maybe(Type::Undefined())) {
+ if (maybe_null) if_nil.Or();
+ if_nil.If<HCompareObjectEqAndBranch>(value,
+ graph()->GetConstantUndefined());
+ }
+
if_nil.Then();
if_nil.Else();
+
if (type->NumClasses() == 1) {
BuildCheckHeapObject(value);
// For ICs, the map checked below is a sentinel map that gets replaced by
@@ -3547,14 +3546,14 @@
HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
- : HGraphBuilder(info),
+ : HGraphBuilder(info, CallInterfaceDescriptor()),
function_state_(NULL),
initial_function_state_(this, info, NORMAL_RETURN, 0),
ast_context_(NULL),
break_scope_(NULL),
inlined_count_(0),
globals_(10, info->zone()),
- osr_(new(info->zone()) HOsrBuilder(this)) {
+ osr_(new (info->zone()) HOsrBuilder(this)) {
// This is not initialized in the initializer list because the
// constructor for the initial state relies on function_state_ == NULL
// to know it's the initial state.
@@ -3641,7 +3640,7 @@
}
-HGraph::HGraph(CompilationInfo* info)
+HGraph::HGraph(CompilationInfo* info, CallInterfaceDescriptor descriptor)
: isolate_(info->isolate()),
next_block_id_(0),
entry_block_(NULL),
@@ -3651,6 +3650,7 @@
uint32_instructions_(NULL),
osr_(NULL),
info_(info),
+ descriptor_(descriptor),
zone_(info->zone()),
is_recursive_(false),
use_optimistic_licm_(false),
@@ -3660,10 +3660,9 @@
no_side_effects_scope_count_(0),
disallow_adding_new_values_(false) {
if (info->IsStub()) {
- CallInterfaceDescriptor descriptor =
- info->code_stub()->GetCallInterfaceDescriptor();
- start_environment_ =
- new (zone_) HEnvironment(zone_, descriptor.GetRegisterParameterCount());
+ // For stubs, explicitly add the context to the environment.
+ start_environment_ = new (zone_)
+ HEnvironment(zone_, descriptor.GetRegisterParameterCount() + 1);
} else {
if (info->is_tracking_positions()) {
info->TraceInlinedFunction(info->shared_info(), SourcePosition::Unknown(),
@@ -4675,12 +4674,11 @@
}
AddInstruction(arguments_object);
- graph()->SetArgumentsObject(arguments_object);
// Handle the arguments and arguments shadow variables specially (they do
// not have declarations).
if (scope->arguments() != NULL) {
- environment()->Bind(scope->arguments(), graph()->GetArgumentsObject());
+ environment()->Bind(scope->arguments(), arguments_object);
}
int rest_index;
@@ -4736,8 +4734,11 @@
}
AddInstruction(function);
// Allocate a block context and store it to the stack frame.
- HInstruction* inner_context = Add<HAllocateBlockContext>(
- outer_context, function, scope->GetScopeInfo(isolate()));
+ HValue* scope_info = Add<HConstant>(scope->GetScopeInfo(isolate()));
+ Add<HPushArguments>(scope_info, function);
+ HInstruction* inner_context = Add<HCallRuntime>(
+ Runtime::FunctionForId(Runtime::kPushBlockContext), 2);
+ inner_context->SetFlag(HValue::kHasNoObservableSideEffects);
HInstruction* instr = Add<HStoreFrameContext>(inner_context);
set_scope(scope);
environment()->BindContext(inner_context);
@@ -4955,9 +4956,8 @@
// will always evaluate to true, in a value context the return value needs
// to be a JSObject.
if (context->IsTest()) {
- TestContext* test = TestContext::cast(context);
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- Goto(test->if_true(), state);
+ context->ReturnValue(graph()->GetConstantTrue());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
Goto(function_return(), state);
@@ -5283,10 +5283,6 @@
DCHECK(current_block() != NULL);
DCHECK(current_block()->HasPredecessor());
- if (!FLAG_optimize_for_in) {
- return Bailout(kForInStatementOptimizationIsDisabled);
- }
-
if (!stmt->each()->IsVariableProxy() ||
!stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
return Bailout(kForInStatementWithNonLocalEachVariable);
@@ -5312,57 +5308,73 @@
void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt,
Variable* each_var,
HValue* enumerable) {
- HInstruction* map;
- HInstruction* array;
- HInstruction* enum_length;
+ Handle<Map> meta_map = isolate()->factory()->meta_map();
bool fast = stmt->for_in_type() == ForInStatement::FAST_FOR_IN;
+ BuildCheckHeapObject(enumerable);
+ Add<HCheckInstanceType>(enumerable, HCheckInstanceType::IS_JS_RECEIVER);
+ Add<HSimulate>(stmt->ToObjectId());
if (fast) {
- map = Add<HForInPrepareMap>(enumerable);
- Add<HSimulate>(stmt->PrepareId());
+ HForInPrepareMap* map = Add<HForInPrepareMap>(enumerable);
+ Push(map);
+ Add<HSimulate>(stmt->EnumId());
+ Drop(1);
+ Add<HCheckMaps>(map, meta_map);
- array = Add<HForInCacheArray>(enumerable, map,
- DescriptorArray::kEnumCacheBridgeCacheIndex);
- enum_length = Add<HMapEnumLength>(map);
+ HForInCacheArray* array = Add<HForInCacheArray>(
+ enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex);
+ HValue* enum_length = BuildEnumLength(map);
- HInstruction* index_cache = Add<HForInCacheArray>(
+ HForInCacheArray* index_cache = Add<HForInCacheArray>(
enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex);
- HForInCacheArray::cast(array)
- ->set_index_cache(HForInCacheArray::cast(index_cache));
- } else {
- Add<HSimulate>(stmt->PrepareId());
- {
- NoObservableSideEffectsScope no_effects(this);
- BuildJSObjectCheck(enumerable, 0);
- }
- Add<HSimulate>(stmt->ToObjectId());
+ array->set_index_cache(index_cache);
- map = graph()->GetConstant1();
- Runtime::FunctionId function_id = Runtime::kGetPropertyNamesFast;
+ Push(map);
+ Push(array);
+ Push(enum_length);
+ Add<HSimulate>(stmt->PrepareId());
+ } else {
+ Runtime::FunctionId function_id = Runtime::kForInEnumerate;
Add<HPushArguments>(enumerable);
- array = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 1);
+ HCallRuntime* array =
+ Add<HCallRuntime>(Runtime::FunctionForId(function_id), 1);
Push(array);
Add<HSimulate>(stmt->EnumId());
Drop(1);
- Handle<Map> array_map = isolate()->factory()->fixed_array_map();
- HValue* check = Add<HCheckMaps>(array, array_map);
- enum_length = AddLoadFixedArrayLength(array, check);
+
+ IfBuilder if_fast(this);
+ if_fast.If<HCompareMap>(array, meta_map);
+ if_fast.Then();
+ {
+ HValue* cache_map = array;
+ HForInCacheArray* cache = Add<HForInCacheArray>(
+ enumerable, cache_map, DescriptorArray::kEnumCacheBridgeCacheIndex);
+ HValue* enum_length = BuildEnumLength(cache_map);
+ Push(cache_map);
+ Push(cache);
+ Push(enum_length);
+ Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE);
+ }
+ if_fast.Else();
+ {
+ Push(graph()->GetConstant1());
+ Push(array);
+ Push(AddLoadFixedArrayLength(array));
+ Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE);
+ }
}
- HInstruction* start_index = Add<HConstant>(0);
-
- Push(map);
- Push(array);
- Push(enum_length);
- Push(start_index);
+ Push(graph()->GetConstant0());
HBasicBlock* loop_entry = BuildLoopEntry(stmt);
// Reload the values to ensure we have up-to-date values inside of the loop.
// This is relevant especially for OSR where the values don't come from the
// computation above, but from the OSR entry block.
- enumerable = environment()->ExpressionStackAt(4);
HValue* index = environment()->ExpressionStackAt(0);
HValue* limit = environment()->ExpressionStackAt(1);
+ HValue* array = environment()->ExpressionStackAt(2);
+ HValue* type = environment()->ExpressionStackAt(3);
+ enumerable = environment()->ExpressionStackAt(4);
// Check that we still have more keys.
HCompareNumericAndBranch* compare_index =
@@ -5382,32 +5394,67 @@
set_current_block(loop_body);
- HValue* key =
- Add<HLoadKeyed>(environment()->ExpressionStackAt(2), // Enum cache.
- index, index, nullptr, FAST_ELEMENTS);
+ // Compute the next enumerated value.
+ HValue* key = Add<HLoadKeyed>(array, index, index, nullptr, FAST_ELEMENTS);
+ HBasicBlock* continue_block = nullptr;
if (fast) {
- // Check if the expected map still matches that of the enumerable.
- // If not just deoptimize.
- Add<HCheckMapValue>(enumerable, environment()->ExpressionStackAt(3));
- Bind(each_var, key);
- } else {
- Add<HPushArguments>(enumerable, key);
- Runtime::FunctionId function_id = Runtime::kForInFilter;
- key = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 2);
- Push(key);
+ // Check if expected map still matches that of the enumerable.
+ Add<HCheckMapValue>(enumerable, type);
Add<HSimulate>(stmt->FilterId());
+ } else {
+ // We need the continue block here to be able to skip over invalidated keys.
+ continue_block = graph()->CreateBasicBlock();
+
+ // We cannot use the IfBuilder here, since we need to be able to jump
+ // over the loop body in case of undefined result from %ForInFilter,
+ // and the poor soul that is the IfBuilder get's really confused about
+ // such "advanced control flow requirements".
+ HBasicBlock* if_fast = graph()->CreateBasicBlock();
+ HBasicBlock* if_slow = graph()->CreateBasicBlock();
+ HBasicBlock* if_slow_pass = graph()->CreateBasicBlock();
+ HBasicBlock* if_slow_skip = graph()->CreateBasicBlock();
+ HBasicBlock* if_join = graph()->CreateBasicBlock();
+
+ // Check if expected map still matches that of the enumerable.
+ HValue* enumerable_map =
+ Add<HLoadNamedField>(enumerable, nullptr, HObjectAccess::ForMap());
+ FinishCurrentBlock(
+ New<HCompareObjectEqAndBranch>(enumerable_map, type, if_fast, if_slow));
+ set_current_block(if_fast);
+ {
+ // The enum cache for enumerable is still valid, no need to check key.
+ Push(key);
+ Goto(if_join);
+ }
+ set_current_block(if_slow);
+ {
+ // Check if key is still valid for enumerable.
+ Add<HPushArguments>(enumerable, key);
+ Runtime::FunctionId function_id = Runtime::kForInFilter;
+ Push(Add<HCallRuntime>(Runtime::FunctionForId(function_id), 2));
+ Add<HSimulate>(stmt->FilterId());
+ FinishCurrentBlock(New<HCompareObjectEqAndBranch>(
+ Top(), graph()->GetConstantUndefined(), if_slow_skip, if_slow_pass));
+ }
+ set_current_block(if_slow_pass);
+ { Goto(if_join); }
+ set_current_block(if_slow_skip);
+ {
+ // The key is no longer valid for enumerable, skip it.
+ Drop(1);
+ Goto(continue_block);
+ }
+ if_join->SetJoinId(stmt->FilterId());
+ set_current_block(if_join);
key = Pop();
- Bind(each_var, key);
- IfBuilder if_undefined(this);
- if_undefined.If<HCompareObjectEqAndBranch>(key,
- graph()->GetConstantUndefined());
- if_undefined.ThenDeopt(Deoptimizer::kUndefined);
- if_undefined.End();
- Add<HSimulate>(stmt->AssignmentId());
}
+ Bind(each_var, key);
+ Add<HSimulate>(stmt->AssignmentId());
+
BreakAndContinueInfo break_info(stmt, scope(), 5);
+ break_info.set_continue_block(continue_block);
{
BreakAndContinueScope push(&break_info, this);
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
@@ -5420,7 +5467,10 @@
set_current_block(body_exit);
HValue* current_index = Pop();
- Push(AddUncasted<HAdd>(current_index, graph()->GetConstant1()));
+ HValue* increment =
+ AddUncasted<HAdd>(current_index, graph()->GetConstant1());
+ increment->ClearFlag(HValue::kCanOverflow);
+ Push(increment);
body_exit = current_block();
}
@@ -5638,7 +5688,7 @@
Handle<Context> script_context = ScriptContextTable::GetContext(
script_contexts, lookup.context_index);
Handle<Object> current_value =
- FixedArray::get(script_context, lookup.slot_index);
+ FixedArray::get(*script_context, lookup.slot_index, isolate());
// If the values is not the hole, it will stay initialized,
// so no need to generate a check.
@@ -6069,9 +6119,7 @@
for (int i = 0; i < length; i++) {
Expression* subexpr = subexprs->at(i);
- if (subexpr->IsSpread()) {
- return Bailout(kSpread);
- }
+ DCHECK(!subexpr->IsSpread());
// If the subexpression is a literal or a simple materialized literal it
// is already set in the cloned array.
@@ -6221,6 +6269,13 @@
return instr;
}
+Handle<FieldType>
+HOptimizedGraphBuilder::PropertyAccessInfo::GetFieldTypeFromMap(
+ Handle<Map> map) const {
+ DCHECK(IsFound());
+ DCHECK(number_ < map->NumberOfOwnDescriptors());
+ return handle(map->instance_descriptors()->GetFieldType(number_), isolate());
+}
bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
PropertyAccessInfo* info) {
@@ -6316,15 +6371,15 @@
Object* raw_accessor =
IsLoad() ? Handle<AccessorPair>::cast(accessors)->getter()
: Handle<AccessorPair>::cast(accessors)->setter();
- if (!raw_accessor->IsJSFunction()) return false;
- Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor));
- if (accessor->shared()->IsApiFunction()) {
- CallOptimization call_optimization(accessor);
- if (call_optimization.is_simple_api_call()) {
- CallOptimization::HolderLookup holder_lookup;
- api_holder_ =
- call_optimization.LookupHolderOfExpectedType(map_, &holder_lookup);
- }
+ if (!raw_accessor->IsJSFunction() &&
+ !raw_accessor->IsFunctionTemplateInfo())
+ return false;
+ Handle<Object> accessor = handle(HeapObject::cast(raw_accessor));
+ CallOptimization call_optimization(accessor);
+ if (call_optimization.is_simple_api_call()) {
+ CallOptimization::HolderLookup holder_lookup;
+ api_holder_ =
+ call_optimization.LookupHolderOfExpectedType(map_, &holder_lookup);
}
accessor_ = accessor;
} else if (IsDataConstant()) {
@@ -6342,35 +6397,24 @@
field_type_ = HType::Tagged();
// Figure out the field type from the accessor map.
- Handle<HeapType> field_type = GetFieldTypeFromMap(map);
+ Handle<FieldType> field_type = GetFieldTypeFromMap(map);
// Collect the (stable) maps from the field type.
- int num_field_maps = field_type->NumClasses();
- if (num_field_maps > 0) {
+ if (field_type->IsClass()) {
DCHECK(access_.representation().IsHeapObject());
- field_maps_.Reserve(num_field_maps, zone());
- HeapType::Iterator<Map> it = field_type->Classes();
- while (!it.Done()) {
- Handle<Map> field_map = it.Current();
- if (!field_map->is_stable()) {
- field_maps_.Clear();
- break;
- }
+ Handle<Map> field_map = field_type->AsClass();
+ if (field_map->is_stable()) {
field_maps_.Add(field_map, zone());
- it.Advance();
}
}
if (field_maps_.is_empty()) {
// Store is not safe if the field map was cleared.
- return IsLoad() || !field_type->Is(HeapType::None());
+ return IsLoad() || !field_type->IsNone();
}
- field_maps_.Sort();
- DCHECK_EQ(num_field_maps, field_maps_.length());
-
- // Determine field HType from field HeapType.
- field_type_ = HType::FromType<HeapType>(field_type);
+ // Determine field HType from field type.
+ field_type_ = HType::FromFieldType(field_type, zone());
DCHECK(field_type_.IsHeapObject());
// Add dependency on the map that introduced the field.
@@ -6381,6 +6425,10 @@
bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
Handle<Map> map = this->map();
+ if (name_->IsPrivate()) {
+ NotFound();
+ return !map->has_hidden_prototype();
+ }
while (map->prototype()->IsJSObject()) {
holder_ = handle(JSObject::cast(map->prototype()));
@@ -6573,7 +6621,8 @@
Push(value);
}
- if (info->NeedsWrappingFor(info->accessor())) {
+ if (info->accessor()->IsJSFunction() &&
+ info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) {
HValue* function = Add<HConstant>(info->accessor());
PushArgumentsFromEnvironment(argument_count);
return New<HCallFunction>(function, argument_count,
@@ -6587,7 +6636,12 @@
}
PushArgumentsFromEnvironment(argument_count);
- return BuildCallConstantFunction(info->accessor(), argument_count);
+ if (!info->accessor()->IsJSFunction()) {
+ Bailout(kInliningBailedOut);
+ return nullptr;
+ }
+ return BuildCallConstantFunction(Handle<JSFunction>::cast(info->accessor()),
+ argument_count);
}
DCHECK(info->IsDataConstant());
@@ -6744,18 +6798,48 @@
}
}
-
-static bool ComputeReceiverTypes(Expression* expr,
- HValue* receiver,
+static bool ComputeReceiverTypes(Expression* expr, HValue* receiver,
SmallMapList** t,
- Zone* zone) {
+ HOptimizedGraphBuilder* builder) {
+ Zone* zone = builder->zone();
SmallMapList* maps = expr->GetReceiverTypes();
*t = maps;
bool monomorphic = expr->IsMonomorphic();
if (maps != NULL && receiver->HasMonomorphicJSObjectType()) {
- Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
- maps->FilterForPossibleTransitions(root_map);
- monomorphic = maps->length() == 1;
+ if (maps->length() > 0) {
+ Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
+ maps->FilterForPossibleTransitions(root_map);
+ monomorphic = maps->length() == 1;
+ } else {
+ // No type feedback, see if we can infer the type. This is safely
+ // possible if the receiver had a known map at some point, and no
+ // map-changing stores have happened to it since.
+ Handle<Map> candidate_map = receiver->GetMonomorphicJSObjectMap();
+ if (candidate_map->is_observed()) return false;
+ for (HInstruction* current = builder->current_block()->last();
+ current != nullptr; current = current->previous()) {
+ if (current->IsBlockEntry()) break;
+ if (current->CheckChangesFlag(kMaps)) {
+ // Only allow map changes that store the candidate map. We don't
+ // need to care which object the map is being written into.
+ if (!current->IsStoreNamedField()) break;
+ HStoreNamedField* map_change = HStoreNamedField::cast(current);
+ if (!map_change->value()->IsConstant()) break;
+ HConstant* map_constant = HConstant::cast(map_change->value());
+ if (!map_constant->representation().IsTagged()) break;
+ Handle<Object> map = map_constant->handle(builder->isolate());
+ if (!map.is_identical_to(candidate_map)) break;
+ }
+ if (current == receiver) {
+ // We made it all the way back to the receiver without encountering
+ // a map change! So we can assume that the receiver still has the
+ // candidate_map we know about.
+ maps->Add(candidate_map, zone);
+ monomorphic = true;
+ break;
+ }
+ }
+ }
}
return monomorphic && CanInlinePropertyAccess(maps->first());
}
@@ -6846,7 +6930,7 @@
ScriptContextTable::GetContext(script_contexts, lookup.context_index);
Handle<Object> current_value =
- FixedArray::get(script_context, lookup.slot_index);
+ FixedArray::get(*script_context, lookup.slot_index, isolate());
// If the values is not the hole, it will stay initialized,
// so no need to generate a check.
@@ -7246,14 +7330,14 @@
// use a generic Keyed Load if we are using the type vector, because
// it has to share information with full code.
HConstant* key = Add<HConstant>(name);
- HLoadKeyedGeneric* result = New<HLoadKeyedGeneric>(
- object, key, function_language_mode(), PREMONOMORPHIC);
+ HLoadKeyedGeneric* result =
+ New<HLoadKeyedGeneric>(object, key, PREMONOMORPHIC);
result->SetVectorAndSlot(vector, slot);
return result;
}
- HLoadNamedGeneric* result = New<HLoadNamedGeneric>(
- object, name, function_language_mode(), PREMONOMORPHIC);
+ HLoadNamedGeneric* result =
+ New<HLoadNamedGeneric>(object, name, PREMONOMORPHIC);
result->SetVectorAndSlot(vector, slot);
return result;
} else {
@@ -7287,8 +7371,8 @@
HValue* object, HValue* key, HValue* value) {
if (access_type == LOAD) {
InlineCacheState initial_state = expr->AsProperty()->GetInlineCacheState();
- HLoadKeyedGeneric* result = New<HLoadKeyedGeneric>(
- object, key, function_language_mode(), initial_state);
+ HLoadKeyedGeneric* result =
+ New<HLoadKeyedGeneric>(object, key, initial_state);
// HLoadKeyedGeneric with vector ics benefits from being encoded as
// MEGAMORPHIC because the vector/slot combo becomes unnecessary.
if (initial_state != MEGAMORPHIC) {
@@ -7370,8 +7454,8 @@
static bool CanInlineElementAccess(Handle<Map> map) {
- return map->IsJSObjectMap() && !map->has_dictionary_elements() &&
- !map->has_sloppy_arguments_elements() &&
+ return map->IsJSObjectMap() &&
+ (map->has_fast_elements() || map->has_fixed_typed_array_elements()) &&
!map->has_indexed_interceptor() && !map->is_access_check_needed();
}
@@ -7664,7 +7748,7 @@
HInstruction* instr = NULL;
SmallMapList* maps;
- bool monomorphic = ComputeReceiverTypes(expr, obj, &maps, zone());
+ bool monomorphic = ComputeReceiverTypes(expr, obj, &maps, this);
bool force_generic = false;
if (expr->GetKeyType() == PROPERTY) {
@@ -7790,7 +7874,7 @@
result = New<HConstant>(argument_count);
}
} else {
- Push(graph()->GetArgumentsObject());
+ CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true);
CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true);
HValue* key = Pop();
Drop(1); // Arguments object.
@@ -7821,7 +7905,7 @@
Expression* expr, FeedbackVectorSlot slot, HValue* object,
Handle<Name> name, HValue* value, bool is_uninitialized) {
SmallMapList* maps;
- ComputeReceiverTypes(expr, object, &maps, zone());
+ ComputeReceiverTypes(expr, object, &maps, this);
DCHECK(maps != NULL);
if (maps->length() > 0) {
@@ -8341,10 +8425,12 @@
CompilationInfo target_info(&parse_info);
Handle<SharedFunctionInfo> target_shared(target->shared());
- if (IsClassConstructor(target_shared->kind())) {
+ if (inlining_kind != CONSTRUCT_CALL_RETURN &&
+ IsClassConstructor(target_shared->kind())) {
TraceInline(target, caller, "target is classConstructor");
return false;
}
+
if (target_shared->HasDebugInfo()) {
TraceInline(target, caller, "target is being debugged");
return false;
@@ -8531,7 +8617,7 @@
// return value will always evaluate to true, in a value context the
// return value is the newly allocated receiver.
if (call_context()->IsTest()) {
- Goto(inlined_test_context()->if_true(), state);
+ inlined_test_context()->ReturnValue(graph()->GetConstantTrue());
} else if (call_context()->IsEffect()) {
Goto(function_return(), state);
} else {
@@ -8554,7 +8640,7 @@
// Falling off the end of a normal inlined function. This basically means
// returning undefined.
if (call_context()->IsTest()) {
- Goto(inlined_test_context()->if_false(), state);
+ inlined_test_context()->ReturnValue(graph()->GetConstantFalse());
} else if (call_context()->IsEffect()) {
Goto(function_return(), state);
} else {
@@ -8617,24 +8703,25 @@
CONSTRUCT_CALL_RETURN);
}
-
-bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
+bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter,
Handle<Map> receiver_map,
BailoutId ast_id,
BailoutId return_id) {
if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
- return TryInline(getter, 0, NULL, ast_id, return_id, GETTER_CALL_RETURN);
+ return getter->IsJSFunction() &&
+ TryInline(Handle<JSFunction>::cast(getter), 0, NULL, ast_id, return_id,
+ GETTER_CALL_RETURN);
}
-
-bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter,
+bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter,
Handle<Map> receiver_map,
BailoutId id,
BailoutId assignment_id,
HValue* implicit_return_value) {
if (TryInlineApiSetter(setter, receiver_map, id)) return true;
- return TryInline(setter, 1, implicit_return_value, id, assignment_id,
- SETTER_CALL_RETURN);
+ return setter->IsJSFunction() &&
+ TryInline(Handle<JSFunction>::cast(setter), 1, implicit_return_value,
+ id, assignment_id, SETTER_CALL_RETURN);
}
@@ -8694,7 +8781,8 @@
Isolate* isolate = jsarray_map->GetIsolate();
Handle<Name> length_string = isolate->factory()->length_string();
DescriptorArray* descriptors = jsarray_map->instance_descriptors();
- int number = descriptors->SearchWithCache(*length_string, *jsarray_map);
+ int number =
+ descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
DCHECK_NE(DescriptorArray::kNotFound, number);
return descriptors->GetDetails(number).IsReadOnly();
}
@@ -9058,6 +9146,7 @@
case kArrayLastIndexOf: {
if (receiver_map.is_null()) return false;
if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
+ if (!receiver_map->prototype()->IsJSObject()) return false;
ElementsKind kind = receiver_map->elements_kind();
if (!IsFastElementsKind(kind)) return false;
if (receiver_map->is_observed()) return false;
@@ -9127,8 +9216,7 @@
kCallApiMethod);
}
-
-bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function,
+bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function,
Handle<Map> receiver_map,
BailoutId ast_id) {
SmallMapList receiver_maps(1, zone());
@@ -9141,8 +9229,7 @@
kCallApiGetter);
}
-
-bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<JSFunction> function,
+bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function,
Handle<Map> receiver_map,
BailoutId ast_id) {
SmallMapList receiver_maps(1, zone());
@@ -9155,15 +9242,14 @@
kCallApiSetter);
}
-
-bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
- HValue* receiver,
- SmallMapList* receiver_maps,
- int argc,
- BailoutId ast_id,
- ApiCallType call_type) {
- if (function->context()->native_context() !=
- top_info()->closure()->context()->native_context()) {
+bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<Object> function,
+ HValue* receiver,
+ SmallMapList* receiver_maps,
+ int argc, BailoutId ast_id,
+ ApiCallType call_type) {
+ if (function->IsJSFunction() &&
+ Handle<JSFunction>::cast(function)->context()->native_context() !=
+ top_info()->closure()->context()->native_context()) {
return false;
}
CallOptimization optimization(function);
@@ -9178,8 +9264,11 @@
// Cannot embed a direct reference to the global proxy map
// as it maybe dropped on deserialization.
CHECK(!isolate()->serializer_enabled());
+ DCHECK(function->IsJSFunction());
DCHECK_EQ(0, receiver_maps->length());
- receiver_maps->Add(handle(function->global_proxy()->map()), zone());
+ receiver_maps->Add(
+ handle(Handle<JSFunction>::cast(function)->global_proxy()->map()),
+ zone());
}
CallOptimization::HolderLookup holder_lookup =
CallOptimization::kHolderNotFound;
@@ -9259,7 +9348,8 @@
HInstruction* call = nullptr;
if (!is_function) {
- CallApiAccessorStub stub(isolate(), is_store, call_data_undefined);
+ CallApiAccessorStub stub(isolate(), is_store, call_data_undefined,
+ !optimization.is_constant_call());
Handle<Code> code = stub.GetCode();
HConstant* code_value = Add<HConstant>(code);
ApiAccessorDescriptor descriptor(isolate());
@@ -9643,6 +9733,9 @@
void HOptimizedGraphBuilder::VisitCall(Call* expr) {
+ if (expr->tail_call_mode() == TailCallMode::kAllow) {
+ return Bailout(kTailCall);
+ }
DCHECK(!HasStackOverflow());
DCHECK(current_block() != NULL);
DCHECK(current_block()->HasPredecessor());
@@ -9657,7 +9750,7 @@
HValue* receiver = Top();
SmallMapList* maps;
- ComputeReceiverTypes(expr, receiver, &maps, zone());
+ ComputeReceiverTypes(expr, receiver, &maps, this);
if (prop->key()->IsPropertyName() && maps->length() > 0) {
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
@@ -9852,7 +9945,7 @@
// Checks whether allocation using the given constructor can be inlined.
static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
return constructor->has_initial_map() &&
- !IsClassConstructor(constructor->shared()->kind()) &&
+ !IsSubclassConstructor(constructor->shared()->kind()) &&
constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
constructor->initial_map()->instance_size() <
HAllocate::kMaxInlineSize;
@@ -10105,31 +10198,6 @@
}
-void HOptimizedGraphBuilder::GenerateDataViewInitialize(
- CallRuntime* expr) {
- ZoneList<Expression*>* arguments = expr->arguments();
-
- DCHECK(arguments->length()== 4);
- CHECK_ALIVE(VisitForValue(arguments->at(0)));
- HValue* obj = Pop();
-
- CHECK_ALIVE(VisitForValue(arguments->at(1)));
- HValue* buffer = Pop();
-
- CHECK_ALIVE(VisitForValue(arguments->at(2)));
- HValue* byte_offset = Pop();
-
- CHECK_ALIVE(VisitForValue(arguments->at(3)));
- HValue* byte_length = Pop();
-
- {
- NoObservableSideEffectsScope scope(this);
- BuildArrayBufferViewInitialization<JSDataView>(
- obj, buffer, byte_offset, byte_length);
- }
-}
-
-
HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements(
ExternalArrayType array_type,
bool is_zero_byte_offset,
@@ -10227,7 +10295,7 @@
HValue* backing_store = AddUncasted<HAdd>(
Add<HConstant>(ExternalReference::fixed_typed_array_base_data_offset()),
- elements, Strength::WEAK, AddOfExternalAndTagged);
+ elements, AddOfExternalAndTagged);
HValue* key = builder.BeginBody(
Add<HConstant>(static_cast<int32_t>(0)),
@@ -10612,8 +10680,7 @@
HConstant* delta = (expr->op() == Token::INC)
? graph()->GetConstant1()
: graph()->GetConstantMinus1();
- HInstruction* instr =
- AddUncasted<HAdd>(Top(), delta, strength(function_language_mode()));
+ HInstruction* instr = AddUncasted<HAdd>(Top(), delta);
if (instr->IsAdd()) {
HAdd* add = HAdd::cast(instr);
add->set_observed_input_representation(1, rep);
@@ -10855,7 +10922,7 @@
Maybe<HConstant*> number =
constant->CopyToTruncatedNumber(isolate(), zone());
if (number.IsJust()) {
- *expected = Type::Number(zone());
+ *expected = Type::Number();
return AddInstruction(number.FromJust());
}
}
@@ -10869,20 +10936,20 @@
// Separate the number type from the rest.
Type* expected_obj =
- Type::Intersect(expected_type, Type::NonNumber(zone()), zone());
+ Type::Intersect(expected_type, Type::NonNumber(), zone());
Type* expected_number =
- Type::Intersect(expected_type, Type::Number(zone()), zone());
+ Type::Intersect(expected_type, Type::Number(), zone());
// We expect to get a number.
// (We need to check first, since Type::None->Is(Type::Any()) == true.
if (expected_obj->Is(Type::None())) {
- DCHECK(!expected_number->Is(Type::None(zone())));
+ DCHECK(!expected_number->Is(Type::None()));
return value;
}
- if (expected_obj->Is(Type::Undefined(zone()))) {
+ if (expected_obj->Is(Type::Undefined())) {
// This is already done by HChange.
- *expected = Type::Union(expected_number, Type::Number(zone()), zone());
+ *expected = Type::Union(expected_number, Type::Number(), zone());
return value;
}
@@ -10907,8 +10974,7 @@
}
HValue* result = HGraphBuilder::BuildBinaryOperation(
expr->op(), left, right, left_type, right_type, result_type,
- fixed_right_arg, allocation_mode, strength(function_language_mode()),
- expr->id());
+ fixed_right_arg, allocation_mode, expr->id());
// Add a simulate after instructions with observable side effects, and
// after phis, which are the result of BuildBinaryOperation when we
// inlined some complex subgraph.
@@ -10924,11 +10990,12 @@
return result;
}
-
-HValue* HGraphBuilder::BuildBinaryOperation(
- Token::Value op, HValue* left, HValue* right, Type* left_type,
- Type* right_type, Type* result_type, Maybe<int> fixed_right_arg,
- HAllocationMode allocation_mode, Strength strength, BailoutId opt_id) {
+HValue* HGraphBuilder::BuildBinaryOperation(Token::Value op, HValue* left,
+ HValue* right, Type* left_type,
+ Type* right_type, Type* result_type,
+ Maybe<int> fixed_right_arg,
+ HAllocationMode allocation_mode,
+ BailoutId opt_id) {
bool maybe_string_add = false;
if (op == Token::ADD) {
// If we are adding constant string with something for which we don't have
@@ -10957,7 +11024,7 @@
Add<HDeoptimize>(
Deoptimizer::kInsufficientTypeFeedbackForLHSOfBinaryOperation,
Deoptimizer::SOFT);
- left_type = Type::Any(zone());
+ left_type = Type::Any();
left_rep = RepresentationFor(left_type);
maybe_string_add = op == Token::ADD;
}
@@ -10966,12 +11033,12 @@
Add<HDeoptimize>(
Deoptimizer::kInsufficientTypeFeedbackForRHSOfBinaryOperation,
Deoptimizer::SOFT);
- right_type = Type::Any(zone());
+ right_type = Type::Any();
right_rep = RepresentationFor(right_type);
maybe_string_add = op == Token::ADD;
}
- if (!maybe_string_add && !is_strong(strength)) {
+ if (!maybe_string_add) {
left = TruncateToNumber(left, &left_type);
right = TruncateToNumber(right, &right_type);
}
@@ -10979,43 +11046,36 @@
// Special case for string addition here.
if (op == Token::ADD &&
(left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
- if (is_strong(strength)) {
- // In strong mode, if the one side of an addition is a string,
- // the other side must be a string too.
+ // Validate type feedback for left argument.
+ if (left_type->Is(Type::String())) {
left = BuildCheckString(left);
+ }
+
+ // Validate type feedback for right argument.
+ if (right_type->Is(Type::String())) {
right = BuildCheckString(right);
- } else {
- // Validate type feedback for left argument.
- if (left_type->Is(Type::String())) {
- left = BuildCheckString(left);
- }
+ }
- // Validate type feedback for right argument.
- if (right_type->Is(Type::String())) {
- right = BuildCheckString(right);
- }
+ // Convert left argument as necessary.
+ if (left_type->Is(Type::Number())) {
+ DCHECK(right_type->Is(Type::String()));
+ left = BuildNumberToString(left, left_type);
+ } else if (!left_type->Is(Type::String())) {
+ DCHECK(right_type->Is(Type::String()));
+ return AddUncasted<HStringAdd>(
+ left, right, allocation_mode.GetPretenureMode(),
+ STRING_ADD_CONVERT_LEFT, allocation_mode.feedback_site());
+ }
- // Convert left argument as necessary.
- if (left_type->Is(Type::Number())) {
- DCHECK(right_type->Is(Type::String()));
- left = BuildNumberToString(left, left_type);
- } else if (!left_type->Is(Type::String())) {
- DCHECK(right_type->Is(Type::String()));
- return AddUncasted<HStringAdd>(
- left, right, allocation_mode.GetPretenureMode(),
- STRING_ADD_CONVERT_LEFT, allocation_mode.feedback_site());
- }
-
- // Convert right argument as necessary.
- if (right_type->Is(Type::Number())) {
- DCHECK(left_type->Is(Type::String()));
- right = BuildNumberToString(right, right_type);
- } else if (!right_type->Is(Type::String())) {
- DCHECK(left_type->Is(Type::String()));
- return AddUncasted<HStringAdd>(
- left, right, allocation_mode.GetPretenureMode(),
- STRING_ADD_CONVERT_RIGHT, allocation_mode.feedback_site());
- }
+ // Convert right argument as necessary.
+ if (right_type->Is(Type::Number())) {
+ DCHECK(left_type->Is(Type::String()));
+ right = BuildNumberToString(right, right_type);
+ } else if (!right_type->Is(Type::String())) {
+ DCHECK(left_type->Is(Type::String()));
+ return AddUncasted<HStringAdd>(
+ left, right, allocation_mode.GetPretenureMode(),
+ STRING_ADD_CONVERT_RIGHT, allocation_mode.feedback_site());
}
// Fast paths for empty constant strings.
@@ -11064,6 +11124,16 @@
allocation_mode.feedback_site());
}
+ // Special case for +x here.
+ if (op == Token::MUL) {
+ if (left->EqualsInteger32Constant(1)) {
+ return BuildToNumber(right);
+ }
+ if (right->EqualsInteger32Constant(1)) {
+ return BuildToNumber(left);
+ }
+ }
+
if (graph()->info()->IsStub()) {
left = EnforceNumberType(left, left_type);
right = EnforceNumberType(right, right_type);
@@ -11084,78 +11154,51 @@
default:
UNREACHABLE();
case Token::ADD:
- function_id =
- is_strong(strength) ? Runtime::kAdd_Strong : Runtime::kAdd;
+ function_id = Runtime::kAdd;
break;
case Token::SUB:
- function_id = is_strong(strength) ? Runtime::kSubtract_Strong
- : Runtime::kSubtract;
+ function_id = Runtime::kSubtract;
break;
case Token::MUL:
- function_id = is_strong(strength) ? Runtime::kMultiply_Strong
- : Runtime::kMultiply;
+ function_id = Runtime::kMultiply;
break;
case Token::DIV:
- function_id =
- is_strong(strength) ? Runtime::kDivide_Strong : Runtime::kDivide;
+ function_id = Runtime::kDivide;
break;
case Token::MOD:
- function_id =
- is_strong(strength) ? Runtime::kModulus_Strong : Runtime::kModulus;
+ function_id = Runtime::kModulus;
break;
case Token::BIT_OR:
- function_id = is_strong(strength) ? Runtime::kBitwiseOr_Strong
- : Runtime::kBitwiseOr;
+ function_id = Runtime::kBitwiseOr;
break;
case Token::BIT_AND:
- function_id = is_strong(strength) ? Runtime::kBitwiseAnd_Strong
- : Runtime::kBitwiseAnd;
+ function_id = Runtime::kBitwiseAnd;
break;
case Token::BIT_XOR:
- function_id = is_strong(strength) ? Runtime::kBitwiseXor_Strong
- : Runtime::kBitwiseXor;
+ function_id = Runtime::kBitwiseXor;
break;
case Token::SAR:
- function_id = is_strong(strength) ? Runtime::kShiftRight_Strong
- : Runtime::kShiftRight;
+ function_id = Runtime::kShiftRight;
break;
case Token::SHR:
- function_id = is_strong(strength) ? Runtime::kShiftRightLogical_Strong
- : Runtime::kShiftRightLogical;
+ function_id = Runtime::kShiftRightLogical;
break;
case Token::SHL:
- function_id = is_strong(strength) ? Runtime::kShiftLeft_Strong
- : Runtime::kShiftLeft;
+ function_id = Runtime::kShiftLeft;
break;
}
Add<HPushArguments>(left, right);
instr = AddUncasted<HCallRuntime>(Runtime::FunctionForId(function_id), 2);
} else {
- if (is_strong(strength) && Token::IsBitOp(op)) {
- // TODO(conradw): This is not efficient, but is necessary to prevent
- // conversion of oddball values to numbers in strong mode. It would be
- // better to prevent the conversion rather than adding a runtime check.
- IfBuilder if_builder(this);
- if_builder.If<HHasInstanceTypeAndBranch>(left, ODDBALL_TYPE);
- if_builder.OrIf<HHasInstanceTypeAndBranch>(right, ODDBALL_TYPE);
- if_builder.Then();
- Add<HCallRuntime>(
- Runtime::FunctionForId(Runtime::kThrowStrongModeImplicitConversion),
- 0);
- if (!graph()->info()->IsStub()) {
- Add<HSimulate>(opt_id, REMOVABLE_SIMULATE);
- }
- if_builder.End();
- }
switch (op) {
case Token::ADD:
- instr = AddUncasted<HAdd>(left, right, strength);
+ instr = AddUncasted<HAdd>(left, right);
break;
case Token::SUB:
- instr = AddUncasted<HSub>(left, right, strength);
+ instr = AddUncasted<HSub>(left, right);
break;
case Token::MUL:
- instr = AddUncasted<HMul>(left, right, strength);
+ instr = AddUncasted<HMul>(left, right);
break;
case Token::MOD: {
if (fixed_right_arg.IsJust() &&
@@ -11168,38 +11211,38 @@
if_same.ElseDeopt(Deoptimizer::kUnexpectedRHSOfBinaryOperation);
right = fixed_right;
}
- instr = AddUncasted<HMod>(left, right, strength);
+ instr = AddUncasted<HMod>(left, right);
break;
}
case Token::DIV:
- instr = AddUncasted<HDiv>(left, right, strength);
+ instr = AddUncasted<HDiv>(left, right);
break;
case Token::BIT_XOR:
case Token::BIT_AND:
- instr = AddUncasted<HBitwise>(op, left, right, strength);
+ instr = AddUncasted<HBitwise>(op, left, right);
break;
case Token::BIT_OR: {
HValue *operand, *shift_amount;
if (left_type->Is(Type::Signed32()) &&
right_type->Is(Type::Signed32()) &&
MatchRotateRight(left, right, &operand, &shift_amount)) {
- instr = AddUncasted<HRor>(operand, shift_amount, strength);
+ instr = AddUncasted<HRor>(operand, shift_amount);
} else {
- instr = AddUncasted<HBitwise>(op, left, right, strength);
+ instr = AddUncasted<HBitwise>(op, left, right);
}
break;
}
case Token::SAR:
- instr = AddUncasted<HSar>(left, right, strength);
+ instr = AddUncasted<HSar>(left, right);
break;
case Token::SHR:
- instr = AddUncasted<HShr>(left, right, strength);
+ instr = AddUncasted<HShr>(left, right);
if (instr->IsShr() && CanBeZero(right)) {
graph()->RecordUint32Instruction(instr);
}
break;
case Token::SHL:
- instr = AddUncasted<HShl>(left, right, strength);
+ instr = AddUncasted<HShl>(left, right);
break;
default:
UNREACHABLE();
@@ -11520,7 +11563,7 @@
Add<HDeoptimize>(
Deoptimizer::kInsufficientTypeFeedbackForCombinedTypeOfBinaryOperation,
Deoptimizer::SOFT);
- combined_type = left_type = right_type = Type::Any(zone());
+ combined_type = left_type = right_type = Type::Any();
}
Representation left_rep = RepresentationFor(left_type);
@@ -11657,8 +11700,7 @@
return result;
} else {
if (combined_rep.IsTagged() || combined_rep.IsNone()) {
- HCompareGeneric* result = Add<HCompareGeneric>(
- left, right, op, strength(function_language_mode()));
+ HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
result->set_observed_input_representation(1, left_rep);
result->set_observed_input_representation(2, right_rep);
if (result->HasObservableSideEffects()) {
@@ -11674,8 +11716,8 @@
HBranch* branch = New<HBranch>(result);
return branch;
} else {
- HCompareNumericAndBranch* result = New<HCompareNumericAndBranch>(
- left, right, op, strength(function_language_mode()));
+ HCompareNumericAndBranch* result =
+ New<HCompareNumericAndBranch>(left, right, op);
result->set_observed_input_representation(left_rep, right_rep);
if (top_info()->is_tracking_positions()) {
result->SetOperandPositions(zone(), left_position, right_position);
@@ -11706,7 +11748,8 @@
} else {
DCHECK_EQ(Token::EQ, expr->op());
Type* type = expr->combined_type()->Is(Type::None())
- ? Type::Any(zone()) : expr->combined_type();
+ ? Type::Any()
+ : expr->combined_type();
HIfContinuation continuation;
BuildCompareNil(value, type, &continuation);
return ast_context()->ReturnContinuation(&continuation, expr->id());
@@ -12149,8 +12192,8 @@
}
-void HOptimizedGraphBuilder::VisitRewritableAssignmentExpression(
- RewritableAssignmentExpression* node) {
+void HOptimizedGraphBuilder::VisitRewritableExpression(
+ RewritableExpression* node) {
CHECK_ALIVE(Visit(node->expression()));
}
@@ -12178,25 +12221,6 @@
}
-void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
- DCHECK(call->arguments()->length() == 1);
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- HValue* value = Pop();
- HHasInstanceTypeAndBranch* result = New<HHasInstanceTypeAndBranch>(
- value, FIRST_FUNCTION_TYPE, LAST_FUNCTION_TYPE);
- return ast_context()->ReturnControl(result, call->id());
-}
-
-
-void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) {
- DCHECK(call->arguments()->length() == 1);
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- HValue* value = Pop();
- HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value);
- return ast_context()->ReturnControl(result, call->id());
-}
-
-
void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
DCHECK(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -12264,6 +12288,30 @@
}
+void HOptimizedGraphBuilder::GenerateToName(CallRuntime* call) {
+ DCHECK_EQ(1, call->arguments()->length());
+ CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+ HValue* input = Pop();
+ if (input->type().IsSmi()) {
+ HValue* result = BuildNumberToString(input, Type::SignedSmall());
+ return ast_context()->ReturnValue(result);
+ } else if (input->type().IsTaggedNumber()) {
+ HValue* result = BuildNumberToString(input, Type::Number());
+ return ast_context()->ReturnValue(result);
+ } else if (input->type().IsString()) {
+ return ast_context()->ReturnValue(input);
+ } else {
+ Callable callable = CodeFactory::ToName(isolate());
+ HValue* stub = Add<HConstant>(callable.code());
+ HValue* values[] = {context(), input};
+ HInstruction* result =
+ New<HCallWithDescriptor>(stub, 0, callable.descriptor(),
+ Vector<HValue*>(values, arraysize(values)));
+ return ast_context()->ReturnInstruction(result, call->id());
+ }
+}
+
+
void HOptimizedGraphBuilder::GenerateToObject(CallRuntime* call) {
DCHECK_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -12276,11 +12324,11 @@
void HOptimizedGraphBuilder::GenerateToString(CallRuntime* call) {
DCHECK_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- Callable callable = CodeFactory::ToString(isolate());
HValue* input = Pop();
if (input->type().IsString()) {
return ast_context()->ReturnValue(input);
} else {
+ Callable callable = CodeFactory::ToString(isolate());
HValue* stub = Add<HConstant>(callable.code());
HValue* values[] = {context(), input};
HInstruction* result =
@@ -12310,16 +12358,13 @@
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Callable callable = CodeFactory::ToNumber(isolate());
HValue* input = Pop();
- if (input->type().IsTaggedNumber()) {
- return ast_context()->ReturnValue(input);
- } else {
- HValue* stub = Add<HConstant>(callable.code());
- HValue* values[] = {context(), input};
- HInstruction* result =
- New<HCallWithDescriptor>(stub, 0, callable.descriptor(),
- Vector<HValue*>(values, arraysize(values)));
- return ast_context()->ReturnInstruction(result, call->id());
+ HValue* result = BuildToNumber(input);
+ if (result->HasObservableSideEffects()) {
+ if (!ast_context()->IsEffect()) Push(result);
+ Add<HSimulate>(call->id(), REMOVABLE_SIMULATE);
+ if (!ast_context()->IsEffect()) result = Pop();
}
+ return ast_context()->ReturnValue(result);
}
@@ -12372,48 +12417,6 @@
}
-// Support for arguments.length and arguments[?].
-void HOptimizedGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
- DCHECK(call->arguments()->length() == 0);
- HInstruction* result = NULL;
- if (function_state()->outer() == NULL) {
- HInstruction* elements = Add<HArgumentsElements>(false);
- result = New<HArgumentsLength>(elements);
- } else {
- // Number of arguments without receiver.
- int argument_count = environment()->
- arguments_environment()->parameter_count() - 1;
- result = New<HConstant>(argument_count);
- }
- return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
-void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
- DCHECK(call->arguments()->length() == 1);
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- HValue* index = Pop();
- HInstruction* result = NULL;
- if (function_state()->outer() == NULL) {
- HInstruction* elements = Add<HArgumentsElements>(false);
- HInstruction* length = Add<HArgumentsLength>(elements);
- HInstruction* checked_index = Add<HBoundsCheck>(index, length);
- result = New<HAccessArgumentsAt>(elements, length, checked_index);
- } else {
- EnsureArgumentsArePushedForAccess();
-
- // Number of arguments without receiver.
- HInstruction* elements = function_state()->arguments_elements();
- int argument_count = environment()->
- arguments_environment()->parameter_count() - 1;
- HInstruction* length = Add<HConstant>(argument_count);
- HInstruction* checked_key = Add<HBoundsCheck>(index, length);
- result = New<HAccessArgumentsAt>(elements, length, checked_key);
- }
- return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
DCHECK(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -12442,27 +12445,6 @@
}
-void HOptimizedGraphBuilder::GenerateJSValueGetValue(CallRuntime* call) {
- DCHECK(call->arguments()->length() == 1);
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- HValue* value = Pop();
- HInstruction* result = Add<HLoadNamedField>(
- value, nullptr,
- HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset));
- return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
-void HOptimizedGraphBuilder::GenerateIsDate(CallRuntime* call) {
- DCHECK_EQ(1, call->arguments()->length());
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- HValue* value = Pop();
- HHasInstanceTypeAndBranch* result =
- New<HHasInstanceTypeAndBranch>(value, JS_DATE_TYPE);
- return ast_context()->ReturnControl(result, call->id());
-}
-
-
void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar(
CallRuntime* call) {
DCHECK(call->arguments()->length() == 3);
@@ -12495,43 +12477,6 @@
}
-void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
- DCHECK(call->arguments()->length() == 2);
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
- HValue* value = Pop();
- HValue* object = Pop();
-
- // Check if object is a JSValue.
- IfBuilder if_objectisvalue(this);
- if_objectisvalue.If<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE);
- if_objectisvalue.Then();
- {
- // Create in-object property store to kValueOffset.
- Add<HStoreNamedField>(object,
- HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset),
- value);
- if (!ast_context()->IsEffect()) {
- Push(value);
- }
- Add<HSimulate>(call->id(), FIXED_SIMULATE);
- }
- if_objectisvalue.Else();
- {
- // Nothing to do in this case.
- if (!ast_context()->IsEffect()) {
- Push(value);
- }
- Add<HSimulate>(call->id(), FIXED_SIMULATE);
- }
- if_objectisvalue.End();
- if (!ast_context()->IsEffect()) {
- Drop(1);
- }
- return ast_context()->ReturnValue(value);
-}
-
-
// Fast support for charCodeAt(n).
void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
DCHECK(call->arguments()->length() == 2);
@@ -12568,25 +12513,18 @@
}
-// Fast support for object equality testing.
-void HOptimizedGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
- DCHECK(call->arguments()->length() == 2);
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
- HValue* right = Pop();
- HValue* left = Pop();
- HCompareObjectEqAndBranch* result =
- New<HCompareObjectEqAndBranch>(left, right);
- return ast_context()->ReturnControl(result, call->id());
-}
-
-
// Fast support for SubString.
void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
DCHECK_EQ(3, call->arguments()->length());
CHECK_ALIVE(VisitExpressions(call->arguments()));
PushArgumentsFromEnvironment(call->arguments()->length());
- HCallStub* result = New<HCallStub>(CodeStub::SubString, 3);
+ Callable callable = CodeFactory::SubString(isolate());
+ HValue* stub = Add<HConstant>(callable.code());
+ HValue* values[] = {context()};
+ HInstruction* result = New<HCallWithDescriptor>(
+ stub, call->arguments()->length(), callable.descriptor(),
+ Vector<HValue*>(values, arraysize(values)));
+ result->set_type(HType::String());
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -12596,7 +12534,12 @@
DCHECK_EQ(4, call->arguments()->length());
CHECK_ALIVE(VisitExpressions(call->arguments()));
PushArgumentsFromEnvironment(call->arguments()->length());
- HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4);
+ Callable callable = CodeFactory::RegExpExec(isolate());
+ HValue* stub = Add<HConstant>(callable.code());
+ HValue* values[] = {context()};
+ HInstruction* result = New<HCallWithDescriptor>(
+ stub, call->arguments()->length(), callable.descriptor(),
+ Vector<HValue*>(values, arraysize(values)));
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -12669,7 +12612,7 @@
DCHECK_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* number = Pop();
- HValue* result = BuildNumberToString(number, Type::Any(zone()));
+ HValue* result = BuildNumberToString(number, Type::Any());
return ast_context()->ReturnValue(result);
}
@@ -12929,16 +12872,6 @@
}
-void HOptimizedGraphBuilder::GenerateFastOneByteArrayJoin(CallRuntime* call) {
- // Simply returning undefined here would be semantically correct and even
- // avoid the bailout. Nevertheless, some ancient benchmarks like SunSpider's
- // string-fasta would tank, because fullcode contains an optimized version.
- // Obviously the fullcode => Crankshaft => bailout => fullcode dance is
- // faster... *sigh*
- return Bailout(kInlinedRuntimeFunctionFastOneByteArrayJoin);
-}
-
-
void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
CallRuntime* call) {
Add<HDebugBreak>();