Commit fd8cebb1 authored by neis's avatar neis Committed by Commit bot

[compiler] Generalize JSContextSpecialization.

With this CL, context loads and stores are "strengthened" by reducing
the incoming context chain and decreasing the depth accordingly,
whenever possible.  This enables more opportunities for specialization
and will let us easily add module context specialization later.

BUG=

Review-Url: https://codereview.chromium.org/2559173003
Cr-Commit-Position: refs/heads/master@{#42334}
parent a6fe748d
......@@ -28,50 +28,81 @@ Reduction JSContextSpecialization::Reduce(Node* node) {
return NoChange();
}
Reduction JSContextSpecialization::SimplifyJSLoadContext(Node* node,
Node* new_context,
size_t new_depth) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
const ContextAccess& access = ContextAccessOf(node->op());
DCHECK_LE(new_depth, access.depth());
if (new_depth == access.depth() &&
new_context == NodeProperties::GetContextInput(node)) {
return NoChange();
}
MaybeHandle<Context> JSContextSpecialization::GetSpecializationContext(
Node* node) {
DCHECK(node->opcode() == IrOpcode::kJSLoadContext ||
node->opcode() == IrOpcode::kJSStoreContext);
Node* const object = NodeProperties::GetContextInput(node);
return NodeProperties::GetSpecializationContext(object, context());
const Operator* op = jsgraph_->javascript()->LoadContext(
new_depth, access.index(), access.immutable());
NodeProperties::ReplaceContextInput(node, new_context);
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
Reduction JSContextSpecialization::SimplifyJSStoreContext(Node* node,
Node* new_context,
size_t new_depth) {
DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
const ContextAccess& access = ContextAccessOf(node->op());
DCHECK_LE(new_depth, access.depth());
if (new_depth == access.depth() &&
new_context == NodeProperties::GetContextInput(node)) {
return NoChange();
}
const Operator* op =
jsgraph_->javascript()->StoreContext(new_depth, access.index());
NodeProperties::ReplaceContextInput(node, new_context);
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
// Get the specialization context from the node.
Handle<Context> context;
if (!GetSpecializationContext(node).ToHandle(&context)) return NoChange();
// Find the right parent context.
const ContextAccess& access = ContextAccessOf(node->op());
for (size_t i = access.depth(); i > 0; --i) {
context = handle(context->previous(), isolate());
size_t depth = access.depth();
// First walk up the context chain in the graph as far as possible.
Node* outer = NodeProperties::GetOuterContext(node, &depth);
Handle<Context> concrete;
if (!NodeProperties::GetSpecializationContext(outer, context())
.ToHandle(&concrete)) {
// We do not have a concrete context object, so we can only partially reduce
// the load by folding-in the outer context node.
return SimplifyJSLoadContext(node, outer, depth);
}
// If the access itself is mutable, only fold-in the parent.
if (!access.immutable()) {
// The access does not have to look up a parent, nothing to fold.
if (access.depth() == 0) {
return NoChange();
// Now walk up the concrete context chain for the remaining depth.
for (; depth > 0; --depth) {
concrete = handle(concrete->previous(), isolate());
}
const Operator* op = jsgraph_->javascript()->LoadContext(
0, access.index(), access.immutable());
NodeProperties::ReplaceContextInput(node, jsgraph_->Constant(context));
NodeProperties::ChangeOp(node, op);
return Changed(node);
if (!access.immutable()) {
// We found the requested context object but since the context slot is
// mutable we can only partially reduce the load.
return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
}
Handle<Object> value =
handle(context->get(static_cast<int>(access.index())), isolate());
// Even though the context slot is immutable, the context might have escaped
// before the function to which it belongs has initialized the slot.
// We must be conservative and check if the value in the slot is currently the
// hole or undefined. If it is neither of these, then it must be initialized.
// We must be conservative and check if the value in the slot is currently
// the hole or undefined. Only if it is neither of these, can we be sure that
// it won't change anymore.
Handle<Object> value(concrete->get(static_cast<int>(access.index())),
isolate());
if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) {
return NoChange();
return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
}
// Success. The context load can be replaced with the constant.
......@@ -86,24 +117,27 @@ Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
// Get the specialization context from the node.
Handle<Context> context;
if (!GetSpecializationContext(node).ToHandle(&context)) return NoChange();
// The access does not have to look up a parent, nothing to fold.
const ContextAccess& access = ContextAccessOf(node->op());
if (access.depth() == 0) {
return NoChange();
size_t depth = access.depth();
// First walk up the context chain in the graph until we reduce the depth to 0
// or hit a node that does not have a CreateXYZContext operator.
Node* outer = NodeProperties::GetOuterContext(node, &depth);
Handle<Context> concrete;
if (!NodeProperties::GetSpecializationContext(outer, context())
.ToHandle(&concrete)) {
// We do not have a concrete context object, so we can only partially reduce
// the load by folding-in the outer context node.
return SimplifyJSStoreContext(node, outer, depth);
}
// Find the right parent context.
for (size_t i = access.depth(); i > 0; --i) {
context = handle(context->previous(), isolate());
// Now walk up the concrete context chain for the remaining depth.
for (; depth > 0; --depth) {
concrete = handle(concrete->previous(), isolate());
}
NodeProperties::ReplaceContextInput(node, jsgraph_->Constant(context));
NodeProperties::ChangeOp(node, javascript()->StoreContext(0, access.index()));
return Changed(node);
return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth);
}
......
......@@ -30,8 +30,10 @@ class JSContextSpecialization final : public AdvancedReducer {
Reduction ReduceJSLoadContext(Node* node);
Reduction ReduceJSStoreContext(Node* node);
// Returns the {Context} to specialize {node} to (if any).
MaybeHandle<Context> GetSpecializationContext(Node* node);
Reduction SimplifyJSStoreContext(Node* node, Node* new_context,
size_t new_depth);
Reduction SimplifyJSLoadContext(Node* node, Node* new_context,
size_t new_depth);
Isolate* isolate() const;
JSOperatorBuilder* javascript() const;
......
......@@ -338,6 +338,17 @@ MaybeHandle<Context> NodeProperties::GetSpecializationContext(
}
// static
Node* NodeProperties::GetOuterContext(Node* node, size_t* depth) {
Node* context = NodeProperties::GetContextInput(node);
while (*depth > 0 &&
IrOpcode::IsContextChainExtendingOpcode(context->opcode())) {
context = NodeProperties::GetContextInput(context);
(*depth)--;
}
return context;
}
// static
Type* NodeProperties::GetTypeOrAny(Node* node) {
return IsTyped(node) ? node->type() : Type::Any();
......
......@@ -132,6 +132,11 @@ class V8_EXPORT_PRIVATE NodeProperties final {
static MaybeHandle<Context> GetSpecializationContext(
Node* node, MaybeHandle<Context> context = MaybeHandle<Context>());
// Walk up the context chain from the given {node} until we reduce the {depth}
// to 0 or hit a node that does not extend the context chain ({depth} will be
// updated accordingly).
static Node* GetOuterContext(Node* node, size_t* depth);
// ---------------------------------------------------------------------------
// Type.
......
......@@ -800,6 +800,10 @@ class V8_EXPORT_PRIVATE IrOpcode {
(kNumberEqual <= value && value <= kStringLessThanOrEqual) ||
(kWord32Equal <= value && value <= kFloat64LessThanOrEqual);
}
static bool IsContextChainExtendingOpcode(Value value) {
return kJSCreateFunctionContext <= value && value <= kJSCreateScriptContext;
}
};
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, IrOpcode::Value);
......
......@@ -18,7 +18,7 @@ namespace compiler {
class ContextSpecializationTester : public HandleAndZoneScope {
public:
ContextSpecializationTester()
explicit ContextSpecializationTester(MaybeHandle<Context> context)
: graph_(new (main_zone()) Graph(main_zone())),
common_(main_zone()),
javascript_(main_zone()),
......@@ -27,7 +27,7 @@ class ContextSpecializationTester : public HandleAndZoneScope {
jsgraph_(main_isolate(), graph(), common(), &javascript_, &simplified_,
&machine_),
reducer_(main_zone(), graph()),
spec_(&reducer_, jsgraph(), MaybeHandle<Context>()) {}
spec_(&reducer_, jsgraph(), context) {}
JSContextSpecialization* spec() { return &spec_; }
Factory* factory() { return main_isolate()->factory(); }
......@@ -37,6 +37,13 @@ class ContextSpecializationTester : public HandleAndZoneScope {
JSGraph* jsgraph() { return &jsgraph_; }
Graph* graph() { return graph_; }
void CheckChangesToValue(Node* node, Handle<HeapObject> expected_value);
void CheckContextInputAndDepthChanges(
Node* node, Handle<Context> expected_new_context_object,
size_t expected_new_depth);
void CheckContextInputAndDepthChanges(Node* node, Node* expected_new_context,
size_t expected_new_depth);
private:
Graph* graph_;
CommonOperatorBuilder common_;
......@@ -48,9 +55,52 @@ class ContextSpecializationTester : public HandleAndZoneScope {
JSContextSpecialization spec_;
};
void ContextSpecializationTester::CheckChangesToValue(
Node* node, Handle<HeapObject> expected_value) {
Reduction r = spec()->Reduce(node);
CHECK(r.Changed());
HeapObjectMatcher match(r.replacement());
CHECK(match.HasValue());
CHECK_EQ(*match.Value(), *expected_value);
}
void ContextSpecializationTester::CheckContextInputAndDepthChanges(
Node* node, Handle<Context> expected_new_context_object,
size_t expected_new_depth) {
ContextAccess access = OpParameter<ContextAccess>(node);
Reduction r = spec()->Reduce(node);
CHECK(r.Changed());
Node* new_context = NodeProperties::GetContextInput(r.replacement());
CHECK_EQ(IrOpcode::kHeapConstant, new_context->opcode());
HeapObjectMatcher match(new_context);
CHECK_EQ(*match.Value(), *expected_new_context_object);
ContextAccess new_access = OpParameter<ContextAccess>(r.replacement());
CHECK_EQ(new_access.depth(), expected_new_depth);
CHECK_EQ(new_access.index(), access.index());
CHECK_EQ(new_access.immutable(), access.immutable());
}
void ContextSpecializationTester::CheckContextInputAndDepthChanges(
Node* node, Node* expected_new_context, size_t expected_new_depth) {
ContextAccess access = OpParameter<ContextAccess>(node);
Reduction r = spec()->Reduce(node);
CHECK(r.Changed());
Node* new_context = NodeProperties::GetContextInput(r.replacement());
CHECK_EQ(new_context, expected_new_context);
ContextAccess new_access = OpParameter<ContextAccess>(r.replacement());
CHECK_EQ(new_access.depth(), expected_new_depth);
CHECK_EQ(new_access.index(), access.index());
CHECK_EQ(new_access.immutable(), access.immutable());
}
static const int slot_index = Context::NATIVE_CONTEXT_INDEX;
TEST(ReduceJSLoadContext) {
ContextSpecializationTester t;
TEST(ReduceJSLoadContext0) {
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
......@@ -114,14 +164,239 @@ TEST(ReduceJSLoadContext) {
CHECK(match.HasValue());
CHECK_EQ(*expected, *match.Value());
}
}
TEST(ReduceJSLoadContext1) {
// The graph's context chain ends in the incoming context parameter:
//
// context2 <-- context1 <-- context0 (= Parameter(0))
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, false), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, true), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 1);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 1);
}
}
TEST(ReduceJSLoadContext2) {
// The graph's context chain ends in a constant context (context_object1),
// which has has another outer context (context_object0).
//
// context2 <-- context1 <-- context0 (= HeapConstant(context_object1))
// context_object1 <~~ context_object0
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Handle<HeapObject> slot_value0 = t.factory()->InternalizeUtf8String("0");
Handle<HeapObject> slot_value1 = t.factory()->InternalizeUtf8String("1");
Handle<Context> context_object0 = t.factory()->NewNativeContext();
Handle<Context> context_object1 = t.factory()->NewNativeContext();
context_object1->set_previous(*context_object0);
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
Node* context0 = t.jsgraph()->Constant(context_object1);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, false), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, true), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
// TODO(titzer): test with other kinds of contexts, e.g. a function context.
// TODO(sigurds): test that loads below create context are not optimized
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, true), context2, start);
t.CheckChangesToValue(load, slot_value1);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context_object0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, true), context2, start);
t.CheckChangesToValue(load, slot_value0);
}
}
TEST(ReduceJSLoadContext3) {
// Like in ReduceJSLoadContext1, the graph's context chain ends in the
// incoming context parameter. However, this time we provide a concrete
// context for this parameter as the "specialization context". We choose
// context_object2 from ReduceJSLoadContext2 for this, so almost all test
// expectations are the same as in ReduceJSLoadContext2.
HandleAndZoneScope handle_zone_scope;
auto factory = handle_zone_scope.main_isolate()->factory();
TEST(ReduceJSStoreContext) {
ContextSpecializationTester t;
Handle<HeapObject> slot_value0 = factory->InternalizeUtf8String("0");
Handle<HeapObject> slot_value1 = factory->InternalizeUtf8String("1");
Handle<Context> context_object0 = factory->NewNativeContext();
Handle<Context> context_object1 = factory->NewNativeContext();
context_object1->set_previous(*context_object0);
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
ContextSpecializationTester t(context_object1);
Node* start = t.graph()->NewNode(t.common()->Start(2));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, false), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, true), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context_object1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, true), context2, start);
t.CheckChangesToValue(load, slot_value1);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context_object0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, true), context2, start);
t.CheckChangesToValue(load, slot_value0);
}
}
TEST(ReduceJSStoreContext0) {
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
......@@ -182,6 +457,158 @@ TEST(ReduceJSStoreContext) {
}
}
TEST(ReduceJSStoreContext1) {
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
context2, context2, start, start);
CHECK(!t.spec()->Reduce(store).Changed());
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context1, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context0, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context0, 1);
}
}
TEST(ReduceJSStoreContext2) {
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Handle<HeapObject> slot_value0 = t.factory()->InternalizeUtf8String("0");
Handle<HeapObject> slot_value1 = t.factory()->InternalizeUtf8String("1");
Handle<Context> context_object0 = t.factory()->NewNativeContext();
Handle<Context> context_object1 = t.factory()->NewNativeContext();
context_object1->set_previous(*context_object0);
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
Node* context0 = t.jsgraph()->Constant(context_object1);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
context2, context2, start, start);
CHECK(!t.spec()->Reduce(store).Changed());
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context1, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context0, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context_object0, 0);
}
}
TEST(ReduceJSStoreContext3) {
HandleAndZoneScope handle_zone_scope;
auto factory = handle_zone_scope.main_isolate()->factory();
Handle<HeapObject> slot_value0 = factory->InternalizeUtf8String("0");
Handle<HeapObject> slot_value1 = factory->InternalizeUtf8String("1");
Handle<Context> context_object0 = factory->NewNativeContext();
Handle<Context> context_object1 = factory->NewNativeContext();
context_object1->set_previous(*context_object0);
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
ContextSpecializationTester t(context_object1);
Node* start = t.graph()->NewNode(t.common()->Start(2));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
context2, context2, start, start);
CHECK(!t.spec()->Reduce(store).Changed());
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context1, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context_object1, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context_object0, 0);
}
}
TEST(SpecializeJSFunction_ToConstant1) {
FunctionTester T(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment