BailoutId ReturnId() const { return BailoutId(local_id(0)); }
BailoutId EvalOrLookupId() const { return BailoutId(local_id(1)); }
+ bool is_uninitialized() const {
+ return IsUninitializedField::decode(bit_field_);
+ }
+ void set_is_uninitialized(bool b) {
+ bit_field_ = IsUninitializedField::update(bit_field_, b);
+ }
+
enum CallType {
POSSIBLY_EVAL_CALL,
GLOBAL_CALL,
: Expression(zone, pos),
call_feedback_slot_(FeedbackVectorICSlot::Invalid()),
expression_(expression),
- arguments_(arguments) {
+ arguments_(arguments),
+ bit_field_(IsUninitializedField::encode(false)) {
if (expression->IsProperty()) {
expression->AsProperty()->mark_for_call();
}
Handle<JSFunction> target_;
Handle<Cell> cell_;
Handle<AllocationSite> allocation_site_;
+ class IsUninitializedField : public BitField8<bool, 0, 1> {};
+ uint8_t bit_field_;
};
void ValueContext::ReturnValue(HValue* value) {
// The value is tracked in the bailout environment, and communicated
// through the environment as the result of the expression.
- if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) {
- owner()->Bailout(kBadValueContextForArgumentsValue);
+ if (value->CheckFlag(HValue::kIsArguments)) {
+ if (flag_ == ARGUMENTS_FAKED) {
+ value = owner()->graph()->GetConstantUndefined();
+ } else if (!arguments_allowed()) {
+ owner()->Bailout(kBadValueContextForArgumentsValue);
+ }
}
owner()->Push(value);
}
}
+void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs,
+ ArgumentsAllowedFlag flag) {
+ for (int i = 0; i < exprs->length(); ++i) {
+ CHECK_ALIVE(VisitForValue(exprs->at(i), flag));
+ }
+}
+
+
bool HOptimizedGraphBuilder::BuildGraph() {
if (current_info()->function()->is_generator()) {
Bailout(kFunctionIsAGenerator);
// is supported.
if (current_info()->scope()->arguments() == NULL) return false;
- ZoneList<Expression*>* args = expr->arguments();
- if (args->length() != 2) return false;
+ if (!CanBeFunctionApplyArguments(expr)) 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;
}
}
+bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) {
+ 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;
+ return true;
+}
+
+
void HOptimizedGraphBuilder::VisitCall(Call* expr) {
DCHECK(!HasStackOverflow());
DCHECK(current_block() != NULL);
if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
- // Push the function under the receiver.
- environment()->SetExpressionStackAt(0, function);
- Push(receiver);
if (function->IsConstant() &&
HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
+ // Push the function under the receiver.
+ environment()->SetExpressionStackAt(0, function);
+ Push(receiver);
+
Handle<JSFunction> known_function = Handle<JSFunction>::cast(
HConstant::cast(function)->handle(isolate()));
expr->set_target(known_function);
}
} else {
- CHECK_ALIVE(VisitExpressions(expr->arguments()));
+ ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED;
+ if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) {
+ // We have to use EAGER deoptimization here because Deoptimizer::SOFT
+ // gets ignored by the always-opt flag, which leads to incorrect code.
+ Add<HDeoptimize>("Insufficient type feedback for call with arguments",
+ Deoptimizer::EAGER);
+ arguments_flag = ARGUMENTS_FAKED;
+ }
+
+ // Push the function under the receiver.
+ environment()->SetExpressionStackAt(0, function);
+ Push(receiver);
+
+ CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag));
CallFunctionFlags flags = receiver->type().IsJSObject()
? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
call = New<HCallFunction>(function, argument_count, flags);
enum ArgumentsAllowedFlag {
ARGUMENTS_NOT_ALLOWED,
- ARGUMENTS_ALLOWED
+ ARGUMENTS_ALLOWED,
+ ARGUMENTS_FAKED
};
#endif
}
}
-
HValue* LookupAndMakeLive(Variable* var) {
HEnvironment* env = environment();
int index = env->IndexFor(var);
// Visit a list of expressions from left to right, each in a value context.
void VisitExpressions(ZoneList<Expression*>* exprs);
+ void VisitExpressions(ZoneList<Expression*>* exprs,
+ ArgumentsAllowedFlag flag);
// Remove the arguments from the bailout environment and emit instructions
// to push them as outgoing parameters.
HInstruction* BuildCallConstantFunction(Handle<JSFunction> target,
int argument_count);
+ bool CanBeFunctionApplyArguments(Call* expr);
+
// The translation state of the currently-being-translated function.
FunctionState* function_state_;
}
+bool TypeFeedbackOracle::CallIsUninitialized(FeedbackVectorICSlot slot) {
+ Handle<Object> value = GetInfo(slot);
+ return value->IsUndefined() ||
+ value.is_identical_to(
+ TypeFeedbackVector::UninitializedSentinel(isolate()));
+}
+
+
bool TypeFeedbackOracle::CallIsMonomorphic(FeedbackVectorICSlot slot) {
Handle<Object> value = GetInfo(slot);
return value->IsAllocationSite() || value->IsJSFunction();
bool LoadIsUninitialized(TypeFeedbackId id);
bool StoreIsUninitialized(TypeFeedbackId id);
+ bool CallIsUninitialized(FeedbackVectorICSlot slot);
bool CallIsMonomorphic(FeedbackVectorICSlot slot);
bool KeyedArrayCallIsHoley(TypeFeedbackId id);
bool CallNewIsMonomorphic(FeedbackVectorSlot slot);
void AstTyper::VisitCall(Call* expr) {
// Collect type feedback.
RECURSE(Visit(expr->expression()));
+ FeedbackVectorICSlot slot = expr->CallFeedbackSlot();
+ expr->set_is_uninitialized(oracle()->CallIsUninitialized(slot));
if (!expr->expression()->IsProperty() &&
expr->IsUsingCallFeedbackSlot(isolate()) &&
- oracle()->CallIsMonomorphic(expr->CallFeedbackSlot())) {
- expr->set_target(oracle()->GetCallTarget(expr->CallFeedbackSlot()));
- Handle<AllocationSite> site =
- oracle()->GetCallAllocationSite(expr->CallFeedbackSlot());
+ oracle()->CallIsMonomorphic(slot)) {
+ expr->set_target(oracle()->GetCallTarget(slot));
+ Handle<AllocationSite> site = oracle()->GetCallAllocationSite(slot);
expr->set_allocation_site(site);
}
--- /dev/null
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function getobj() {
+ return { bar : function() { return 0}};
+}
+
+function foo() {
+ var obj = getobj();
+ var length = arguments.length;
+ if (length == 0) {
+ obj.bar();
+ } else {
+ obj.bar.apply(obj, arguments);
+ }
+}
+
+foo();
+foo();
+%OptimizeFunctionOnNextCall(foo);
+foo();
+assertOptimized(foo);
+foo(10);
+assertUnoptimized(foo);
+%ClearFunctionTypeFeedback(foo);