[turbofan] Move JSCallFunction specialization to JSCallReducer.
This is the first part to refactoring the JSNativeContextSpecialization class, which has grown way too big recently. Also don't collect cross context feedback for the CallIC in general. Neither TurboFan nor Crankshaft can make any use of cross context JSFunction feedback that is collected by the CallIC, so there's no point in gathering that feedback at all (it just complicates the checking that is necessary in the compilers). What we should do instead at some point (when Crankshaft becomes less important) is to collect the SharedFunctionInfo as feedback for those cases. R=yangguo@chromium.org BUG=v8:4470 LOG=n Review URL: https://codereview.chromium.org/1451273002 Cr-Commit-Position: refs/heads/master@{#32022}
This commit is contained in:
parent
a240df84a3
commit
e5edd66d07
@ -2559,6 +2559,14 @@ void CallICStub::Generate(MacroAssembler* masm) {
|
|||||||
__ cmp(r1, r4);
|
__ cmp(r1, r4);
|
||||||
__ b(eq, &miss);
|
__ b(eq, &miss);
|
||||||
|
|
||||||
|
// Make sure the function belongs to the same native context (which implies
|
||||||
|
// the same global object).
|
||||||
|
__ ldr(r4, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||||
|
__ ldr(r4, ContextOperand(r4, Context::GLOBAL_OBJECT_INDEX));
|
||||||
|
__ ldr(ip, GlobalObjectOperand());
|
||||||
|
__ cmp(r4, ip);
|
||||||
|
__ b(ne, &miss);
|
||||||
|
|
||||||
// Update stats.
|
// Update stats.
|
||||||
__ ldr(r4, FieldMemOperand(r2, with_types_offset));
|
__ ldr(r4, FieldMemOperand(r2, with_types_offset));
|
||||||
__ add(r4, r4, Operand(Smi::FromInt(1)));
|
__ add(r4, r4, Operand(Smi::FromInt(1)));
|
||||||
|
@ -2945,6 +2945,14 @@ void CallICStub::Generate(MacroAssembler* masm) {
|
|||||||
__ Cmp(function, x5);
|
__ Cmp(function, x5);
|
||||||
__ B(eq, &miss);
|
__ B(eq, &miss);
|
||||||
|
|
||||||
|
// Make sure the function belongs to the same native context (which implies
|
||||||
|
// the same global object).
|
||||||
|
__ Ldr(x4, FieldMemOperand(function, JSFunction::kContextOffset));
|
||||||
|
__ Ldr(x4, ContextMemOperand(x4, Context::GLOBAL_OBJECT_INDEX));
|
||||||
|
__ Ldr(x4, GlobalObjectMemOperand());
|
||||||
|
__ Cmp(x4, x5);
|
||||||
|
__ B(ne, &miss);
|
||||||
|
|
||||||
// Update stats.
|
// Update stats.
|
||||||
__ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
|
__ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
|
||||||
__ Adds(x4, x4, Operand(Smi::FromInt(1)));
|
__ Adds(x4, x4, Operand(Smi::FromInt(1)));
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "src/compiler/js-graph.h"
|
#include "src/compiler/js-graph.h"
|
||||||
#include "src/compiler/node-matchers.h"
|
#include "src/compiler/node-matchers.h"
|
||||||
|
#include "src/compiler/simplified-operator.h"
|
||||||
#include "src/objects-inl.h"
|
#include "src/objects-inl.h"
|
||||||
#include "src/type-feedback-vector-inl.h"
|
#include "src/type-feedback-vector-inl.h"
|
||||||
|
|
||||||
@ -38,23 +39,12 @@ VectorSlotPair CallCountFeedback(VectorSlotPair p) {
|
|||||||
|
|
||||||
|
|
||||||
Reduction JSCallReducer::Reduce(Node* node) {
|
Reduction JSCallReducer::Reduce(Node* node) {
|
||||||
if (node->opcode() == IrOpcode::kJSCallFunction) {
|
switch (node->opcode()) {
|
||||||
HeapObjectMatcher m(node->InputAt(0));
|
case IrOpcode::kJSCallFunction:
|
||||||
if (m.HasValue() && m.Value()->IsJSFunction()) {
|
return ReduceJSCallFunction(node);
|
||||||
Handle<SharedFunctionInfo> shared(
|
|
||||||
Handle<JSFunction>::cast(m.Value())->shared(), isolate());
|
|
||||||
if (shared->HasBuiltinFunctionId()) {
|
|
||||||
switch (shared->builtin_function_id()) {
|
|
||||||
case kFunctionApply:
|
|
||||||
return ReduceFunctionPrototypeApply(node);
|
|
||||||
case kFunctionCall:
|
|
||||||
return ReduceFunctionPrototypeCall(node);
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NoChange();
|
return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +123,9 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
|
|||||||
// to ensure any exception is thrown in the correct context.
|
// to ensure any exception is thrown in the correct context.
|
||||||
NodeProperties::ReplaceContextInput(
|
NodeProperties::ReplaceContextInput(
|
||||||
node, jsgraph()->HeapConstant(handle(apply->context(), isolate())));
|
node, jsgraph()->HeapConstant(handle(apply->context(), isolate())));
|
||||||
return Changed(node);
|
// Try to further reduce the JSCallFunction {node}.
|
||||||
|
Reduction const reduction = ReduceJSCallFunction(node);
|
||||||
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -168,7 +160,88 @@ Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
|
|||||||
node, javascript()->CallFunction(arity, p.language_mode(),
|
node, javascript()->CallFunction(arity, p.language_mode(),
|
||||||
CallCountFeedback(p.feedback()),
|
CallCountFeedback(p.feedback()),
|
||||||
convert_mode, p.tail_call_mode()));
|
convert_mode, p.tail_call_mode()));
|
||||||
|
// Try to further reduce the JSCallFunction {node}.
|
||||||
|
Reduction const reduction = ReduceJSCallFunction(node);
|
||||||
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
|
||||||
|
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
|
||||||
|
CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
|
||||||
|
Node* target = NodeProperties::GetValueInput(node, 0);
|
||||||
|
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
||||||
|
Node* control = NodeProperties::GetControlInput(node);
|
||||||
|
Node* effect = NodeProperties::GetEffectInput(node);
|
||||||
|
|
||||||
|
// Try to specialize JSCallFunction {node}s with constant {target}s.
|
||||||
|
HeapObjectMatcher m(target);
|
||||||
|
if (m.HasValue()) {
|
||||||
|
if (m.Value()->IsJSFunction()) {
|
||||||
|
Handle<SharedFunctionInfo> shared(
|
||||||
|
Handle<JSFunction>::cast(m.Value())->shared(), isolate());
|
||||||
|
|
||||||
|
// Raise a TypeError if the {target} is a "classConstructor".
|
||||||
|
if (IsClassConstructor(shared->kind())) {
|
||||||
|
NodeProperties::RemoveFrameStateInput(node, 0);
|
||||||
|
NodeProperties::RemoveValueInputs(node);
|
||||||
|
NodeProperties::ChangeOp(
|
||||||
|
node, javascript()->CallRuntime(
|
||||||
|
Runtime::kThrowConstructorNonCallableError, 0));
|
||||||
return Changed(node);
|
return Changed(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for known builtin functions.
|
||||||
|
if (shared->HasBuiltinFunctionId()) {
|
||||||
|
switch (shared->builtin_function_id()) {
|
||||||
|
case kFunctionApply:
|
||||||
|
return ReduceFunctionPrototypeApply(node);
|
||||||
|
case kFunctionCall:
|
||||||
|
return ReduceFunctionPrototypeCall(node);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Don't mess with other {node}s that have a constant {target}.
|
||||||
|
// TODO(bmeurer): Also support optimizing bound functions and proxies here.
|
||||||
|
return NoChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not much we can do if deoptimization support is disabled.
|
||||||
|
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
|
||||||
|
|
||||||
|
// Extract feedback from the {node} using the CallICNexus.
|
||||||
|
if (!p.feedback().IsValid()) return NoChange();
|
||||||
|
CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||||
|
Handle<Object> feedback(nexus.GetFeedback(), isolate());
|
||||||
|
if (feedback->IsWeakCell()) {
|
||||||
|
Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
|
||||||
|
if (cell->value()->IsJSFunction()) {
|
||||||
|
// Check that the {target} is still the {target_function}.
|
||||||
|
Node* target_function = jsgraph()->HeapConstant(
|
||||||
|
handle(JSFunction::cast(cell->value()), isolate()));
|
||||||
|
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
|
||||||
|
target, target_function);
|
||||||
|
Node* branch =
|
||||||
|
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
|
||||||
|
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||||
|
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
|
||||||
|
effect, if_false);
|
||||||
|
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
|
||||||
|
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
|
||||||
|
control = graph()->NewNode(common()->IfTrue(), branch);
|
||||||
|
|
||||||
|
// Specialize the JSCallFunction node to the {target_function}.
|
||||||
|
NodeProperties::ReplaceValueInput(node, target_function, 0);
|
||||||
|
NodeProperties::ReplaceControlInput(node, control);
|
||||||
|
|
||||||
|
// Try to further reduce the JSCallFunction {node}.
|
||||||
|
Reduction const reduction = ReduceJSCallFunction(node);
|
||||||
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -178,10 +251,20 @@ Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
|
|||||||
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
|
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
|
||||||
|
|
||||||
|
|
||||||
|
CommonOperatorBuilder* JSCallReducer::common() const {
|
||||||
|
return jsgraph()->common();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
JSOperatorBuilder* JSCallReducer::javascript() const {
|
JSOperatorBuilder* JSCallReducer::javascript() const {
|
||||||
return jsgraph()->javascript();
|
return jsgraph()->javascript();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
|
||||||
|
return jsgraph()->simplified();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace compiler
|
} // namespace compiler
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#ifndef V8_COMPILER_JS_CALL_REDUCER_H_
|
#ifndef V8_COMPILER_JS_CALL_REDUCER_H_
|
||||||
#define V8_COMPILER_JS_CALL_REDUCER_H_
|
#define V8_COMPILER_JS_CALL_REDUCER_H_
|
||||||
|
|
||||||
|
#include "src/base/flags.h"
|
||||||
#include "src/compiler/graph-reducer.h"
|
#include "src/compiler/graph-reducer.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
@ -12,30 +13,47 @@ namespace internal {
|
|||||||
namespace compiler {
|
namespace compiler {
|
||||||
|
|
||||||
// Forward declarations.
|
// Forward declarations.
|
||||||
|
class CommonOperatorBuilder;
|
||||||
class JSGraph;
|
class JSGraph;
|
||||||
class JSOperatorBuilder;
|
class JSOperatorBuilder;
|
||||||
|
class SimplifiedOperatorBuilder;
|
||||||
|
|
||||||
|
|
||||||
// Performs strength reduction on {JSCallFunction} nodes, which might allow
|
// Performs strength reduction on {JSCallFunction} nodes, which might allow
|
||||||
// inlining or other optimizations to be performed afterwards.
|
// inlining or other optimizations to be performed afterwards.
|
||||||
class JSCallReducer final : public Reducer {
|
class JSCallReducer final : public Reducer {
|
||||||
public:
|
public:
|
||||||
explicit JSCallReducer(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
|
// Flags that control the mode of operation.
|
||||||
|
enum Flag {
|
||||||
|
kNoFlags = 0u,
|
||||||
|
kDeoptimizationEnabled = 1u << 0,
|
||||||
|
};
|
||||||
|
typedef base::Flags<Flag> Flags;
|
||||||
|
|
||||||
|
JSCallReducer(JSGraph* jsgraph, Flags flags)
|
||||||
|
: jsgraph_(jsgraph), flags_(flags) {}
|
||||||
|
|
||||||
Reduction Reduce(Node* node) final;
|
Reduction Reduce(Node* node) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Reduction ReduceFunctionPrototypeApply(Node* node);
|
Reduction ReduceFunctionPrototypeApply(Node* node);
|
||||||
Reduction ReduceFunctionPrototypeCall(Node* node);
|
Reduction ReduceFunctionPrototypeCall(Node* node);
|
||||||
|
Reduction ReduceJSCallFunction(Node* node);
|
||||||
|
|
||||||
Graph* graph() const;
|
Graph* graph() const;
|
||||||
|
Flags flags() const { return flags_; }
|
||||||
JSGraph* jsgraph() const { return jsgraph_; }
|
JSGraph* jsgraph() const { return jsgraph_; }
|
||||||
Isolate* isolate() const;
|
Isolate* isolate() const;
|
||||||
|
CommonOperatorBuilder* common() const;
|
||||||
JSOperatorBuilder* javascript() const;
|
JSOperatorBuilder* javascript() const;
|
||||||
|
SimplifiedOperatorBuilder* simplified() const;
|
||||||
|
|
||||||
JSGraph* const jsgraph_;
|
JSGraph* const jsgraph_;
|
||||||
|
Flags const flags_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DEFINE_OPERATORS_FOR_FLAGS(JSCallReducer::Flags)
|
||||||
|
|
||||||
} // namespace compiler
|
} // namespace compiler
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -38,8 +38,6 @@ JSNativeContextSpecialization::JSNativeContextSpecialization(
|
|||||||
|
|
||||||
Reduction JSNativeContextSpecialization::Reduce(Node* node) {
|
Reduction JSNativeContextSpecialization::Reduce(Node* node) {
|
||||||
switch (node->opcode()) {
|
switch (node->opcode()) {
|
||||||
case IrOpcode::kJSCallFunction:
|
|
||||||
return ReduceJSCallFunction(node);
|
|
||||||
case IrOpcode::kJSLoadNamed:
|
case IrOpcode::kJSLoadNamed:
|
||||||
return ReduceJSLoadNamed(node);
|
return ReduceJSLoadNamed(node);
|
||||||
case IrOpcode::kJSStoreNamed:
|
case IrOpcode::kJSStoreNamed:
|
||||||
@ -55,56 +53,6 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Reduction JSNativeContextSpecialization::ReduceJSCallFunction(Node* node) {
|
|
||||||
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
|
|
||||||
CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
|
|
||||||
Node* target = NodeProperties::GetValueInput(node, 0);
|
|
||||||
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
|
||||||
Node* control = NodeProperties::GetControlInput(node);
|
|
||||||
Node* effect = NodeProperties::GetEffectInput(node);
|
|
||||||
|
|
||||||
// Not much we can do if deoptimization support is disabled.
|
|
||||||
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
|
|
||||||
|
|
||||||
// Don't mess with JSCallFunction nodes that have a constant {target}.
|
|
||||||
if (HeapObjectMatcher(target).HasValue()) return NoChange();
|
|
||||||
if (!p.feedback().IsValid()) return NoChange();
|
|
||||||
CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
|
||||||
Handle<Object> feedback(nexus.GetFeedback(), isolate());
|
|
||||||
if (feedback->IsWeakCell()) {
|
|
||||||
Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
|
|
||||||
if (cell->value()->IsJSFunction()) {
|
|
||||||
// Avoid cross-context leaks, meaning don't embed references to functions
|
|
||||||
// in other native contexts.
|
|
||||||
Handle<JSFunction> function(JSFunction::cast(cell->value()), isolate());
|
|
||||||
if (function->context()->native_context() != *native_context()) {
|
|
||||||
return NoChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the {target} is still the {target_function}.
|
|
||||||
Node* target_function = jsgraph()->HeapConstant(function);
|
|
||||||
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
|
|
||||||
target, target_function);
|
|
||||||
Node* branch =
|
|
||||||
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
|
|
||||||
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
|
||||||
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
|
|
||||||
effect, if_false);
|
|
||||||
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
|
|
||||||
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
|
|
||||||
control = graph()->NewNode(common()->IfTrue(), branch);
|
|
||||||
|
|
||||||
// Specialize the JSCallFunction node to the {target_function}.
|
|
||||||
NodeProperties::ReplaceValueInput(node, target_function, 0);
|
|
||||||
NodeProperties::ReplaceControlInput(node, control);
|
|
||||||
return Changed(node);
|
|
||||||
}
|
|
||||||
// TODO(bmeurer): Also support optimizing bound functions and proxies here.
|
|
||||||
}
|
|
||||||
return NoChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||||
Node* node, Node* value, MapHandleList const& receiver_maps,
|
Node* node, Node* value, MapHandleList const& receiver_maps,
|
||||||
Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
|
Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
|
||||||
|
@ -50,7 +50,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
|||||||
Reduction Reduce(Node* node) final;
|
Reduction Reduce(Node* node) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Reduction ReduceJSCallFunction(Node* node);
|
|
||||||
Reduction ReduceJSLoadNamed(Node* node);
|
Reduction ReduceJSLoadNamed(Node* node);
|
||||||
Reduction ReduceJSStoreNamed(Node* node);
|
Reduction ReduceJSStoreNamed(Node* node);
|
||||||
Reduction ReduceJSLoadProperty(Node* node);
|
Reduction ReduceJSLoadProperty(Node* node);
|
||||||
|
@ -177,6 +177,15 @@ void NodeProperties::RemoveNonValueInputs(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void NodeProperties::RemoveValueInputs(Node* node) {
|
||||||
|
int value_input_count = node->op()->ValueInputCount();
|
||||||
|
while (--value_input_count >= 0) {
|
||||||
|
node->RemoveInput(value_input_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void NodeProperties::MergeControlToEnd(Graph* graph,
|
void NodeProperties::MergeControlToEnd(Graph* graph,
|
||||||
CommonOperatorBuilder* common,
|
CommonOperatorBuilder* common,
|
||||||
Node* node) {
|
Node* node) {
|
||||||
|
@ -86,6 +86,7 @@ class NodeProperties final {
|
|||||||
static void ReplaceFrameStateInput(Node* node, int index, Node* frame_state);
|
static void ReplaceFrameStateInput(Node* node, int index, Node* frame_state);
|
||||||
static void RemoveFrameStateInput(Node* node, int index);
|
static void RemoveFrameStateInput(Node* node, int index);
|
||||||
static void RemoveNonValueInputs(Node* node);
|
static void RemoveNonValueInputs(Node* node);
|
||||||
|
static void RemoveValueInputs(Node* node);
|
||||||
|
|
||||||
// Merge the control node {node} into the end of the graph, introducing a
|
// Merge the control node {node} into the end of the graph, introducing a
|
||||||
// merge node or expanding an existing merge node if necessary.
|
// merge node or expanding an existing merge node if necessary.
|
||||||
|
@ -538,7 +538,10 @@ struct InliningPhase {
|
|||||||
data->common());
|
data->common());
|
||||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||||
data->common(), data->machine());
|
data->common(), data->machine());
|
||||||
JSCallReducer call_reducer(data->jsgraph());
|
JSCallReducer call_reducer(data->jsgraph(),
|
||||||
|
data->info()->is_deoptimization_enabled()
|
||||||
|
? JSCallReducer::kDeoptimizationEnabled
|
||||||
|
: JSCallReducer::kNoFlags);
|
||||||
JSContextSpecialization context_specialization(
|
JSContextSpecialization context_specialization(
|
||||||
&graph_reducer, data->jsgraph(),
|
&graph_reducer, data->jsgraph(),
|
||||||
data->info()->is_function_context_specializing()
|
data->info()->is_function_context_specializing()
|
||||||
|
@ -2212,6 +2212,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
|
|||||||
__ cmp(edi, ecx);
|
__ cmp(edi, ecx);
|
||||||
__ j(equal, &miss);
|
__ j(equal, &miss);
|
||||||
|
|
||||||
|
// Make sure the function belongs to the same native context (which implies
|
||||||
|
// the same global object).
|
||||||
|
__ mov(ecx, FieldOperand(edi, JSFunction::kContextOffset));
|
||||||
|
__ mov(ecx, ContextOperand(ecx, Context::GLOBAL_OBJECT_INDEX));
|
||||||
|
__ cmp(ecx, GlobalObjectOperand());
|
||||||
|
__ j(not_equal, &miss);
|
||||||
|
|
||||||
// Update stats.
|
// Update stats.
|
||||||
__ add(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
|
__ add(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
|
||||||
|
|
||||||
|
@ -2310,6 +2310,12 @@ void CallIC::HandleMiss(Handle<Object> function) {
|
|||||||
if (array_function.is_identical_to(js_function)) {
|
if (array_function.is_identical_to(js_function)) {
|
||||||
// Alter the slot.
|
// Alter the slot.
|
||||||
nexus->ConfigureMonomorphicArray();
|
nexus->ConfigureMonomorphicArray();
|
||||||
|
} else if (js_function->context()->native_context() !=
|
||||||
|
*isolate()->native_context()) {
|
||||||
|
// Don't collect cross-native context feedback for the CallIC.
|
||||||
|
// TODO(bmeurer): We should collect the SharedFunctionInfo as
|
||||||
|
// feedback in this case instead.
|
||||||
|
nexus->ConfigureMegamorphic();
|
||||||
} else {
|
} else {
|
||||||
nexus->ConfigureMonomorphic(js_function);
|
nexus->ConfigureMonomorphic(js_function);
|
||||||
}
|
}
|
||||||
|
@ -2682,6 +2682,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
|
|||||||
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t0);
|
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t0);
|
||||||
__ Branch(&miss, eq, a1, Operand(t0));
|
__ Branch(&miss, eq, a1, Operand(t0));
|
||||||
|
|
||||||
|
// Make sure the function belongs to the same native context (which implies
|
||||||
|
// the same global object).
|
||||||
|
__ lw(t0, FieldMemOperand(a1, JSFunction::kContextOffset));
|
||||||
|
__ lw(t0, ContextOperand(t0, Context::GLOBAL_OBJECT_INDEX));
|
||||||
|
__ lw(t1, GlobalObjectOperand());
|
||||||
|
__ Branch(&miss, ne, t0, Operand(t1));
|
||||||
|
|
||||||
// Update stats.
|
// Update stats.
|
||||||
__ lw(t0, FieldMemOperand(a2, with_types_offset));
|
__ lw(t0, FieldMemOperand(a2, with_types_offset));
|
||||||
__ Addu(t0, t0, Operand(Smi::FromInt(1)));
|
__ Addu(t0, t0, Operand(Smi::FromInt(1)));
|
||||||
|
@ -2758,6 +2758,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
|
|||||||
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, a4);
|
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, a4);
|
||||||
__ Branch(&miss, eq, a1, Operand(a4));
|
__ Branch(&miss, eq, a1, Operand(a4));
|
||||||
|
|
||||||
|
// Make sure the function belongs to the same native context (which implies
|
||||||
|
// the same global object).
|
||||||
|
__ ld(t0, FieldMemOperand(a1, JSFunction::kContextOffset));
|
||||||
|
__ ld(t0, ContextOperand(t0, Context::GLOBAL_OBJECT_INDEX));
|
||||||
|
__ ld(t1, GlobalObjectOperand());
|
||||||
|
__ Branch(&miss, ne, t0, Operand(t1));
|
||||||
|
|
||||||
// Update stats.
|
// Update stats.
|
||||||
__ ld(a4, FieldMemOperand(a2, with_types_offset));
|
__ ld(a4, FieldMemOperand(a2, with_types_offset));
|
||||||
__ Daddu(a4, a4, Operand(Smi::FromInt(1)));
|
__ Daddu(a4, a4, Operand(Smi::FromInt(1)));
|
||||||
|
@ -2051,6 +2051,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
|
|||||||
__ cmpp(rdi, rcx);
|
__ cmpp(rdi, rcx);
|
||||||
__ j(equal, &miss);
|
__ j(equal, &miss);
|
||||||
|
|
||||||
|
// Make sure the function belongs to the same native context (which implies
|
||||||
|
// the same global object).
|
||||||
|
__ movp(rcx, FieldOperand(rdi, JSFunction::kContextOffset));
|
||||||
|
__ movp(rcx, ContextOperand(rcx, Context::GLOBAL_OBJECT_INDEX));
|
||||||
|
__ cmpp(rcx, GlobalObjectOperand());
|
||||||
|
__ j(not_equal, &miss);
|
||||||
|
|
||||||
// Update stats.
|
// Update stats.
|
||||||
__ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(1));
|
__ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(1));
|
||||||
|
|
||||||
|
@ -3674,19 +3674,16 @@ TEST(IncrementalMarkingPreservesMonomorphicCallIC) {
|
|||||||
v8::Local<v8::Value> fun1, fun2;
|
v8::Local<v8::Value> fun1, fun2;
|
||||||
v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
|
v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext();
|
||||||
{
|
{
|
||||||
LocalContext env;
|
|
||||||
CompileRun("function fun() {};");
|
CompileRun("function fun() {};");
|
||||||
fun1 = env->Global()->Get(env.local(), v8_str("fun")).ToLocalChecked();
|
fun1 = CcTest::global()->Get(ctx, v8_str("fun")).ToLocalChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
LocalContext env;
|
|
||||||
CompileRun("function fun() {};");
|
CompileRun("function fun() {};");
|
||||||
fun2 = env->Global()->Get(env.local(), v8_str("fun")).ToLocalChecked();
|
fun2 = CcTest::global()->Get(ctx, v8_str("fun")).ToLocalChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare function f that contains type feedback for closures
|
// Prepare function f that contains type feedback for the two closures.
|
||||||
// originating from two different native contexts.
|
|
||||||
CHECK(CcTest::global()->Set(ctx, v8_str("fun1"), fun1).FromJust());
|
CHECK(CcTest::global()->Set(ctx, v8_str("fun1"), fun1).FromJust());
|
||||||
CHECK(CcTest::global()->Set(ctx, v8_str("fun2"), fun2).FromJust());
|
CHECK(CcTest::global()->Set(ctx, v8_str("fun2"), fun2).FromJust());
|
||||||
CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
|
CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
|
||||||
|
Loading…
Reference in New Issue
Block a user