summaryrefslogtreecommitdiff
path: root/deps/v8/src/hydrogen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/hydrogen.cc')
-rw-r--r--deps/v8/src/hydrogen.cc393
1 files changed, 274 insertions, 119 deletions
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc
index 301e7e40fa..6184bb9e46 100644
--- a/deps/v8/src/hydrogen.cc
+++ b/deps/v8/src/hydrogen.cc
@@ -4,14 +4,13 @@
#include "src/hydrogen.h"
-#include <algorithm>
+#include <sstream>
#include "src/v8.h"
#include "src/allocation-site-scopes.h"
-#include "src/codegen.h"
+#include "src/ast-numbering.h"
#include "src/full-codegen.h"
-#include "src/hashmap.h"
#include "src/hydrogen-bce.h"
#include "src/hydrogen-bch.h"
#include "src/hydrogen-canonicalize.h"
@@ -42,7 +41,6 @@
#include "src/parser.h"
#include "src/runtime/runtime.h"
#include "src/scopeinfo.h"
-#include "src/scopes.h"
#include "src/typing.h"
#if V8_TARGET_ARCH_IA32
@@ -147,7 +145,7 @@ void HBasicBlock::AddInstruction(HInstruction* instr,
entry->set_position(position);
} else {
DCHECK(!FLAG_hydrogen_track_positions ||
- !graph()->info()->IsOptimizing());
+ !graph()->info()->IsOptimizing() || instr->IsAbnormalExit());
}
first_ = last_ = entry;
}
@@ -2626,16 +2624,15 @@ void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements,
}
-HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
- ElementsKind kind,
- HValue* capacity) {
+HValue* HGraphBuilder::BuildAllocateAndInitializeArray(ElementsKind kind,
+ HValue* capacity) {
// The HForceRepresentation is to prevent possible deopt on int-smi
// conversion after allocation but before the new object fields are set.
capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity);
- HValue* new_elements = BuildAllocateElements(kind, size_in_bytes);
- BuildInitializeElementsHeader(new_elements, kind, capacity);
- return new_elements;
+ HValue* new_array = BuildAllocateElements(kind, size_in_bytes);
+ BuildInitializeElementsHeader(new_array, kind, capacity);
+ return new_array;
}
@@ -2690,9 +2687,8 @@ HInstruction* HGraphBuilder::AddElementAccess(
DCHECK(val == NULL);
HLoadKeyed* load = Add<HLoadKeyed>(
elements, checked_key, dependency, elements_kind, load_mode);
- if (FLAG_opt_safe_uint32_operations &&
- (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
- elements_kind == UINT32_ELEMENTS)) {
+ if (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) {
graph()->RecordUint32Instruction(load);
}
return load;
@@ -2754,8 +2750,8 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
(Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >>
ElementsKindToShiftSize(new_kind)));
- HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
- new_kind, new_capacity);
+ HValue* new_elements =
+ BuildAllocateAndInitializeArray(new_kind, new_capacity);
BuildCopyElements(elements, kind, new_elements,
new_kind, length, new_capacity);
@@ -2789,12 +2785,6 @@ void HGraphBuilder::BuildFillElementsWithValue(HValue* elements,
}
}
- // Since we're about to store a hole value, the store instruction below must
- // assume an elements kind that supports heap object values.
- if (IsFastSmiOrObjectElementsKind(elements_kind)) {
- elements_kind = FAST_HOLEY_ELEMENTS;
- }
-
if (initial_capacity >= 0) {
for (int i = 0; i < initial_capacity; i++) {
HInstruction* key = Add<HConstant>(i);
@@ -2832,10 +2822,40 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
? Add<HConstant>(factory->the_hole_value())
: Add<HConstant>(nan_double);
+ // Since we're about to store a hole value, the store instruction below must
+ // assume an elements kind that supports heap object values.
+ if (IsFastSmiOrObjectElementsKind(elements_kind)) {
+ elements_kind = FAST_HOLEY_ELEMENTS;
+ }
+
BuildFillElementsWithValue(elements, elements_kind, from, to, hole);
}
+void HGraphBuilder::BuildCopyProperties(HValue* from_properties,
+ HValue* to_properties, HValue* length,
+ HValue* capacity) {
+ ElementsKind kind = FAST_ELEMENTS;
+
+ BuildFillElementsWithValue(to_properties, kind, length, capacity,
+ graph()->GetConstantUndefined());
+
+ LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
+
+ HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT);
+
+ key = AddUncasted<HSub>(key, graph()->GetConstant1());
+ key->ClearFlag(HValue::kCanOverflow);
+
+ HValue* element =
+ Add<HLoadKeyed>(from_properties, key, static_cast<HValue*>(NULL), kind);
+
+ Add<HStoreKeyed>(to_properties, key, element, kind);
+
+ builder.EndBody();
+}
+
+
void HGraphBuilder::BuildCopyElements(HValue* from_elements,
ElementsKind from_elements_kind,
HValue* to_elements,
@@ -2879,10 +2899,6 @@ void HGraphBuilder::BuildCopyElements(HValue* from_elements,
length, NULL);
}
- if (capacity == NULL) {
- capacity = AddLoadFixedArrayLength(to_elements);
- }
-
LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
HValue* key = builder.BeginBody(length, graph()->GetConstant0(),
@@ -3408,7 +3424,7 @@ void HBasicBlock::FinishExit(HControlInstruction* instruction,
}
-OStream& operator<<(OStream& os, const HBasicBlock& b) {
+std::ostream& operator<<(std::ostream& os, const HBasicBlock& b) {
return os << "B" << b.block_id();
}
@@ -3431,8 +3447,9 @@ HGraph::HGraph(CompilationInfo* info)
maximum_environment_size_(0),
no_side_effects_scope_count_(0),
disallow_adding_new_values_(false),
- next_inline_id_(0),
- inlined_functions_(5, info->zone()) {
+ inlined_functions_(FLAG_hydrogen_track_positions ? 5 : 0, info->zone()),
+ inlining_id_to_function_id_(FLAG_hydrogen_track_positions ? 5 : 0,
+ info->zone()) {
if (info->IsStub()) {
CallInterfaceDescriptor descriptor =
info->code_stub()->GetCallInterfaceDescriptor();
@@ -3492,9 +3509,7 @@ int HGraph::TraceInlinedFunction(
os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get()
<< ") id{" << info()->optimization_id() << "," << id << "} ---\n";
{
- ConsStringIteratorOp op;
StringCharacterStream stream(String::cast(script->source()),
- &op,
shared->start_position());
// fun->end_position() points to the last character in the stream. We
// need to compensate by adding one to calculate the length.
@@ -3512,14 +3527,15 @@ int HGraph::TraceInlinedFunction(
}
}
- int inline_id = next_inline_id_++;
+ int inline_id = inlining_id_to_function_id_.length();
+ inlining_id_to_function_id_.Add(id, zone());
if (inline_id != 0) {
CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
OFStream os(tracing_scope.file());
os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{"
<< info()->optimization_id() << "," << id << "} AS " << inline_id
- << " AT " << position << endl;
+ << " AT " << position << std::endl;
}
return inline_id;
@@ -3531,8 +3547,8 @@ int HGraph::SourcePositionToScriptPosition(HSourcePosition pos) {
return pos.raw();
}
- return inlined_functions_[pos.inlining_id()].start_position() +
- pos.position();
+ const int id = inlining_id_to_function_id_[pos.inlining_id()];
+ return inlined_functions_[id].start_position() + pos.position();
}
@@ -4384,7 +4400,7 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) {
// Must be performed before canonicalization to ensure that Canonicalize
// will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
// zero.
- if (FLAG_opt_safe_uint32_operations) Run<HUint32AnalysisPhase>();
+ Run<HUint32AnalysisPhase>();
if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>();
@@ -5603,6 +5619,8 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
+ // It is safe to use [[Put]] here because the boilerplate already
+ // contains computed properties with an uninitialized value.
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
CHECK_ALIVE(VisitForValue(value));
@@ -6096,7 +6114,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
if (IsAccessor()) return true;
Handle<Map> map = this->map();
- map->LookupTransition(NULL, *name_, &lookup_);
+ map->LookupTransition(NULL, *name_, NONE, &lookup_);
if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) {
// Construct the object field access.
int descriptor = transition()->LastAdded();
@@ -6289,7 +6307,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
HControlInstruction* smi_check = NULL;
handled_string = false;
- for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
+ for (i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name);
if (info.type()->Is(Type::String())) {
if (handled_string) continue;
@@ -6367,7 +6385,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
// know about and do not want to handle ones we've never seen. Otherwise
// use a generic IC.
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
- FinishExitWithHardDeoptimization("Uknown map in polymorphic access");
+ FinishExitWithHardDeoptimization("Unknown map in polymorphic access");
} else {
HInstruction* instr = BuildNamedGeneric(access_type, expr, object, name,
value);
@@ -6426,16 +6444,19 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
bool is_uninitialized) {
if (!prop->key()->IsPropertyName()) {
// Keyed store.
- HValue* value = environment()->ExpressionStackAt(0);
- HValue* key = environment()->ExpressionStackAt(1);
- HValue* object = environment()->ExpressionStackAt(2);
+ HValue* value = Pop();
+ HValue* key = Pop();
+ HValue* object = Pop();
bool has_side_effects = false;
- HandleKeyedElementAccess(object, key, value, expr, ast_id, return_id, STORE,
- &has_side_effects);
- Drop(3);
- Push(value);
- Add<HSimulate>(return_id, REMOVABLE_SIMULATE);
- return ast_context()->ReturnValue(Pop());
+ HValue* result = HandleKeyedElementAccess(
+ object, key, value, expr, ast_id, return_id, STORE, &has_side_effects);
+ if (has_side_effects) {
+ if (!ast_context()->IsEffect()) Push(value);
+ Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
+ if (!ast_context()->IsEffect()) Drop(1);
+ }
+ if (result == NULL) return;
+ return ast_context()->ReturnValue(value);
}
// Named store.
@@ -6920,6 +6941,12 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
}
+static bool CanInlineElementAccess(Handle<Map> map) {
+ return map->IsJSObjectMap() && !map->has_slow_elements_kind() &&
+ !map->has_indexed_interceptor();
+}
+
+
HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
HValue* object,
HValue* key,
@@ -6937,7 +6964,7 @@ HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
Handle<Map> most_general_consolidated_map;
for (int i = 0; i < maps->length(); ++i) {
Handle<Map> map = maps->at(i);
- if (!map->IsJSObjectMap()) return NULL;
+ if (!CanInlineElementAccess(map)) return NULL;
// Don't allow mixing of JSArrays with JSObjects.
if (map->instance_type() == JS_ARRAY_TYPE) {
if (has_non_js_array_access) return NULL;
@@ -7013,8 +7040,9 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
MapHandleList possible_transitioned_maps(maps->length());
for (int i = 0; i < maps->length(); ++i) {
Handle<Map> map = maps->at(i);
+ DCHECK(!map->IsStringMap());
ElementsKind elements_kind = map->elements_kind();
- if (IsFastElementsKind(elements_kind) &&
+ if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) &&
elements_kind != GetInitialFastElementsKind()) {
possible_transitioned_maps.Add(map);
}
@@ -7055,8 +7083,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
if (untransitionable_maps.length() == 1) {
Handle<Map> untransitionable_map = untransitionable_maps[0];
HInstruction* instr = NULL;
- if (untransitionable_map->has_slow_elements_kind() ||
- !untransitionable_map->IsJSObjectMap()) {
+ if (!CanInlineElementAccess(untransitionable_map)) {
instr = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key,
val));
} else {
@@ -7065,14 +7092,13 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
store_mode);
}
*has_side_effects |= instr->HasObservableSideEffects();
- return access_type == STORE ? NULL : instr;
+ return access_type == STORE ? val : instr;
}
HBasicBlock* join = graph()->CreateBasicBlock();
for (int i = 0; i < untransitionable_maps.length(); ++i) {
Handle<Map> map = untransitionable_maps[i];
- if (!map->IsJSObjectMap()) continue;
ElementsKind elements_kind = map->elements_kind();
HBasicBlock* this_map = graph()->CreateBasicBlock();
HBasicBlock* other_map = graph()->CreateBasicBlock();
@@ -7082,7 +7108,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
set_current_block(this_map);
HInstruction* access = NULL;
- if (IsDictionaryElementsKind(elements_kind)) {
+ if (!CanInlineElementAccess(map)) {
access = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key,
val));
} else {
@@ -7118,7 +7144,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
NoObservableSideEffectsScope scope(this);
FinishExitWithHardDeoptimization("Unknown map in polymorphic element access");
set_current_block(join);
- return access_type == STORE ? NULL : Pop();
+ return access_type == STORE ? val : Pop();
}
@@ -7156,8 +7182,14 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone());
bool force_generic = false;
- if (access_type == STORE &&
- (monomorphic || (types != NULL && !types->is_empty()))) {
+ if (access_type == STORE && expr->GetKeyType() == PROPERTY) {
+ // Non-Generic accesses assume that elements are being accessed, and will
+ // deopt for non-index keys, which the IC knows will occur.
+ // TODO(jkummerow): Consider adding proper support for property accesses.
+ force_generic = true;
+ monomorphic = false;
+ } else if (access_type == STORE &&
+ (monomorphic || (types != NULL && !types->is_empty()))) {
// Stores can't be mono/polymorphic if their prototype chain has dictionary
// elements. However a receiver map that has dictionary elements itself
// should be left to normal mono/poly behavior (the other maps may benefit
@@ -7170,11 +7202,24 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
break;
}
}
+ } else if (access_type == LOAD && !monomorphic &&
+ (types != NULL && !types->is_empty())) {
+ // Polymorphic loads have to go generic if any of the maps are strings.
+ // If some, but not all of the maps are strings, we should go generic
+ // because polymorphic access wants to key on ElementsKind and isn't
+ // compatible with strings.
+ for (int i = 0; i < types->length(); i++) {
+ Handle<Map> current_map = types->at(i);
+ if (current_map->IsStringMap()) {
+ force_generic = true;
+ break;
+ }
+ }
}
if (monomorphic) {
Handle<Map> map = types->first();
- if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) {
+ if (!CanInlineElementAccess(map)) {
instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key,
val));
} else {
@@ -7804,7 +7849,7 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
// step, but don't transfer ownership to target_info.
target_info.SetAstValueFactory(top_info()->ast_value_factory(), false);
Handle<SharedFunctionInfo> target_shared(target->shared());
- if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) {
+ if (!Compiler::ParseAndAnalyze(&target_info)) {
if (target_info.isolate()->has_pending_exception()) {
// Parse or scope error, never optimize this function.
SetStackOverflow();
@@ -8082,9 +8127,9 @@ bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter,
}
-bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function,
- Call* expr,
- int arguments_count) {
+bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
+ Call* expr,
+ int arguments_count) {
return TryInline(function,
arguments_count,
NULL,
@@ -8136,13 +8181,22 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
- Call* expr,
- HValue* receiver,
- Handle<Map> receiver_map) {
+ Call* expr, Handle<JSFunction> function, Handle<Map> receiver_map,
+ int args_count_no_receiver) {
+ if (!function->shared()->HasBuiltinFunctionId()) return false;
+ BuiltinFunctionId id = function->shared()->builtin_function_id();
+ int argument_count = args_count_no_receiver + 1; // Plus receiver.
+
+ if (receiver_map.is_null()) {
+ HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
+ if (receiver->IsConstant() &&
+ HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
+ receiver_map =
+ handle(Handle<HeapObject>::cast(
+ HConstant::cast(receiver)->handle(isolate()))->map());
+ }
+ }
// Try to inline calls like Math.* as operations in the calling function.
- if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
- BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
- int argument_count = expr->arguments()->length() + 1; // Plus receiver.
switch (id) {
case kStringCharCodeAt:
case kStringCharAt:
@@ -8251,7 +8305,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
if (receiver_map->is_observed()) return false;
if (!receiver_map->is_extensible()) return false;
- Drop(expr->arguments()->length());
+ Drop(args_count_no_receiver);
HValue* result;
HValue* reduced_length;
HValue* receiver = Pop();
@@ -8327,7 +8381,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
BuildCheckPrototypeMaps(prototype, Handle<JSObject>());
- const int argc = expr->arguments()->length();
+ const int argc = args_count_no_receiver;
if (argc != 1) return false;
HValue* value_to_push = Pop();
@@ -8384,7 +8438,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
// Threshold for fast inlined Array.shift().
HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
- Drop(expr->arguments()->length());
+ Drop(args_count_no_receiver);
HValue* receiver = Pop();
HValue* function = Pop();
HValue* result;
@@ -8690,7 +8744,47 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
}
-bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
+void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function,
+ int arguments_count) {
+ Handle<JSFunction> known_function;
+ int args_count_no_receiver = arguments_count - 1;
+ if (function->IsConstant() &&
+ HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
+ HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
+ Handle<Map> receiver_map;
+ if (receiver->IsConstant() &&
+ HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
+ receiver_map =
+ handle(Handle<HeapObject>::cast(
+ HConstant::cast(receiver)->handle(isolate()))->map());
+ }
+
+ known_function =
+ Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate()));
+ if (TryInlineBuiltinMethodCall(expr, known_function, receiver_map,
+ args_count_no_receiver)) {
+ if (FLAG_trace_inlining) {
+ PrintF("Inlining builtin ");
+ known_function->ShortPrint();
+ PrintF("\n");
+ }
+ return;
+ }
+
+ if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
+ return;
+ }
+ }
+
+ PushArgumentsFromEnvironment(arguments_count);
+ HInvokeFunction* call =
+ New<HInvokeFunction>(function, known_function, arguments_count);
+ Drop(1); // Function
+ ast_context()->ReturnInstruction(call, expr->id());
+}
+
+
+bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
DCHECK(expr->expression()->IsProperty());
if (!expr->IsMonomorphic()) {
@@ -8698,27 +8792,45 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
}
Handle<Map> function_map = expr->GetReceiverTypes()->first();
if (function_map->instance_type() != JS_FUNCTION_TYPE ||
- !expr->target()->shared()->HasBuiltinFunctionId() ||
- expr->target()->shared()->builtin_function_id() != kFunctionApply) {
+ !expr->target()->shared()->HasBuiltinFunctionId()) {
return false;
}
- if (current_info()->scope()->arguments() == NULL) return false;
+ switch (expr->target()->shared()->builtin_function_id()) {
+ case kFunctionCall: {
+ if (expr->arguments()->length() == 0) return false;
+ BuildFunctionCall(expr);
+ return true;
+ }
+ case kFunctionApply: {
+ // For .apply, only the pattern f.apply(receiver, arguments)
+ // is supported.
+ if (current_info()->scope()->arguments() == NULL) return false;
- ZoneList<Expression*>* args = expr->arguments();
- if (args->length() != 2) return false;
+ ZoneList<Expression*>* args = expr->arguments();
+ if (args->length() != 2) return false;
+
+ VariableProxy* arg_two = args->at(1)->AsVariableProxy();
+ if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
+ HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
+ if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
+ BuildFunctionApply(expr);
+ return true;
+ }
+ default: { return false; }
+ }
+ UNREACHABLE();
+}
- VariableProxy* arg_two = args->at(1)->AsVariableProxy();
- if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
- HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
- if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
- // Found pattern f.apply(receiver, arguments).
- CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
+void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) {
+ ZoneList<Expression*>* args = expr->arguments();
+ CHECK_ALIVE(VisitForValue(args->at(0)));
HValue* receiver = Pop(); // receiver
HValue* function = Pop(); // f
Drop(1); // apply
+ Handle<Map> function_map = expr->GetReceiverTypes()->first();
HValue* checked_function = AddCheckMap(function, function_map);
if (function_state()->outer() == NULL) {
@@ -8730,7 +8842,6 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
length,
elements);
ast_context()->ReturnInstruction(result, expr->id());
- return true;
} else {
// We are inside inlined function and we know exactly what is inside
// arguments object. But we need to be able to materialize at deopt.
@@ -8744,23 +8855,33 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
for (int i = 1; i < arguments_count; i++) {
Push(arguments_values->at(i));
}
+ HandleIndirectCall(expr, function, arguments_count);
+ }
+}
- Handle<JSFunction> known_function;
- if (function->IsConstant() &&
- HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
- known_function = Handle<JSFunction>::cast(
- HConstant::cast(function)->handle(isolate()));
- int args_count = arguments_count - 1; // Excluding receiver.
- if (TryInlineApply(known_function, expr, args_count)) return true;
- }
- PushArgumentsFromEnvironment(arguments_count);
- HInvokeFunction* call = New<HInvokeFunction>(
- function, known_function, arguments_count);
- Drop(1); // Function.
- ast_context()->ReturnInstruction(call, expr->id());
- return true;
- }
+// f.call(...)
+void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) {
+ HValue* function = Top(); // f
+ Handle<Map> function_map = expr->GetReceiverTypes()->first();
+ HValue* checked_function = AddCheckMap(function, function_map);
+
+ // f and call are on the stack in the unoptimized code
+ // during evaluation of the arguments.
+ CHECK_ALIVE(VisitExpressions(expr->arguments()));
+
+ int args_length = expr->arguments()->length();
+ int receiver_index = args_length - 1;
+ // Patch the receiver.
+ HValue* receiver = BuildWrapReceiver(
+ environment()->ExpressionStackAt(receiver_index), checked_function);
+ environment()->SetExpressionStackAt(receiver_index, receiver);
+
+ // Call must not be on the stack from now on.
+ int call_index = args_length + 1;
+ environment()->RemoveExpressionStackAt(call_index);
+
+ HandleIndirectCall(expr, function, args_length);
}
@@ -9026,11 +9147,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
HConstant::cast(function)->handle(isolate()));
expr->set_target(known_function);
- if (TryCallApply(expr)) return;
+ if (TryIndirectCall(expr)) return;
CHECK_ALIVE(VisitExpressions(expr->arguments()));
Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
- if (TryInlineBuiltinMethodCall(expr, receiver, map)) {
+ if (TryInlineBuiltinMethodCall(expr, known_function, map,
+ expr->arguments()->length())) {
if (FLAG_trace_inlining) {
PrintF("Inlining builtin ");
known_function->ShortPrint();
@@ -9084,7 +9206,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
LookupIterator::OWN_SKIP_INTERCEPTOR);
GlobalPropertyAccess type = LookupGlobalProperty(var, &it, LOAD);
if (type == kUseCell) {
- Handle<GlobalObject> global(current_info()->global_object());
known_global_function = expr->ComputeGlobalTarget(global, &it);
}
if (known_global_function) {
@@ -10438,8 +10559,7 @@ HValue* HGraphBuilder::BuildBinaryOperation(
break;
case Token::SHR:
instr = AddUncasted<HShr>(left, right);
- if (FLAG_opt_safe_uint32_operations && instr->IsShr() &&
- CanBeZero(right)) {
+ if (instr->IsShr() && CanBeZero(right)) {
graph()->RecordUint32Instruction(instr);
}
break;
@@ -11437,6 +11557,29 @@ void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
}
+void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) {
+ DCHECK(call->arguments()->length() == 1);
+ CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+ HValue* value = Pop();
+ HIfContinuation continuation;
+ IfBuilder if_proxy(this);
+
+ HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value);
+ if_proxy.And();
+ HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap());
+ HValue* instance_type = Add<HLoadNamedField>(
+ map, static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType());
+ if_proxy.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(FIRST_JS_PROXY_TYPE), Token::GTE);
+ if_proxy.And();
+ if_proxy.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(LAST_JS_PROXY_TYPE), Token::LTE);
+
+ if_proxy.CaptureContinuation(&continuation);
+ return ast_context()->ReturnContinuation(&continuation, call->id());
+}
+
+
void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
}
@@ -12068,6 +12211,18 @@ void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
}
+HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) {
+ int count = index_from_top + 1;
+ int index = values_.length() - count;
+ DCHECK(HasExpressionAt(index));
+ // Simulate popping 'count' elements and then
+ // pushing 'count - 1' elements back.
+ pop_count_ += Max(count - push_count_, 0);
+ push_count_ = Max(push_count_ - count, 0) + (count - 1);
+ return values_.Remove(index);
+}
+
+
void HEnvironment::Drop(int count) {
for (int i = 0; i < count; ++i) {
Pop();
@@ -12167,7 +12322,7 @@ HEnvironment* HEnvironment::CopyForInlining(
}
-OStream& operator<<(OStream& os, const HEnvironment& env) {
+std::ostream& operator<<(std::ostream& os, const HEnvironment& env) {
for (int i = 0; i < env.length(); i++) {
if (i == 0) os << "parameters\n";
if (i == env.parameter_count()) os << "specials\n";
@@ -12299,9 +12454,9 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
for (int j = 0; j < total; ++j) {
HPhi* phi = current->phis()->at(j);
PrintIndent();
- OStringStream os;
+ std::ostringstream os;
os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n";
- trace_.Add(os.c_str());
+ trace_.Add(os.str().c_str());
}
}
@@ -12311,7 +12466,7 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
HInstruction* instruction = it.Current();
int uses = instruction->UseCount();
PrintIndent();
- OStringStream os;
+ std::ostringstream os;
os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction;
if (FLAG_hydrogen_track_positions &&
instruction->has_position() &&
@@ -12322,7 +12477,7 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
os << pos.position();
}
os << " <|@\n";
- trace_.Add(os.c_str());
+ trace_.Add(os.str().c_str());
}
}
@@ -12340,9 +12495,9 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
trace_.Add("%d ",
LifetimePosition::FromInstructionIndex(i).Value());
linstr->PrintTo(&trace_);
- OStringStream os;
+ std::ostringstream os;
os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n";
- trace_.Add(os.c_str());
+ trace_.Add(os.str().c_str());
}
}
}
@@ -12442,15 +12597,14 @@ void HStatistics::Initialize(CompilationInfo* info) {
}
-void HStatistics::Print(const char* stats_name) {
+void HStatistics::Print() {
PrintF(
"\n"
"----------------------------------------"
"----------------------------------------\n"
- "--- %s timing results:\n"
+ "--- Hydrogen timing results:\n"
"----------------------------------------"
- "----------------------------------------\n",
- stats_name);
+ "----------------------------------------\n");
base::TimeDelta sum;
for (int i = 0; i < times_.length(); ++i) {
sum += times_[i];
@@ -12489,9 +12643,10 @@ void HStatistics::Print(const char* stats_name) {
double normalized_time = source_size_in_kb > 0
? total.InMillisecondsF() / source_size_in_kb
: 0;
- double normalized_size_in_kb = source_size_in_kb > 0
- ? total_size_ / 1024 / source_size_in_kb
- : 0;
+ double normalized_size_in_kb =
+ source_size_in_kb > 0
+ ? static_cast<double>(total_size_) / 1024 / source_size_in_kb
+ : 0;
PrintF("%33s %8.3f ms %7.3f kB allocated\n",
"Average per kB source", normalized_time, normalized_size_in_kb);
}