From: bmeurer@chromium.org Date: Tue, 30 Sep 2014 10:42:44 +0000 (+0000) Subject: [turbofan] Some javascript operators are globally shared singletons. X-Git-Tag: upstream/4.7.83~6619 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c1ee6247cae116c54093df116c479ab04a9fdfed;p=platform%2Fupstream%2Fv8.git [turbofan] Some javascript operators are globally shared singletons. Also cleanup the interface, and make the parameter class/accessors explicit to work-around the type-unsafety of OpParameter. TEST=compiler-unittests,cctest,mjsunit R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/613683002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24322 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/BUILD.gn b/BUILD.gn index 5ba74eb..bfc7683 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -520,6 +520,7 @@ source_set("v8_base") { "src/compiler/js-graph.h", "src/compiler/js-inlining.cc", "src/compiler/js-inlining.h", + "src/compiler/js-operator.cc", "src/compiler/js-operator.h", "src/compiler/js-typed-lowering.cc", "src/compiler/js-typed-lowering.h", diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 01cde01..d33b05a 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -75,7 +75,7 @@ bool AstGraphBuilder::CreateGraph() { // Emit tracing call if requested to do so. if (FLAG_trace) { - NewNode(javascript()->Runtime(Runtime::kTraceEnter, 0)); + NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0)); } // Visit implicit declaration of the function name. @@ -87,7 +87,7 @@ bool AstGraphBuilder::CreateGraph() { VisitDeclarations(scope->declarations()); // TODO(mstarzinger): This should do an inlined stack check. - Node* node = NewNode(javascript()->Runtime(Runtime::kStackGuard, 0)); + Node* node = NewNode(javascript()->CallRuntime(Runtime::kStackGuard, 0)); PrepareFrameState(node, BailoutId::FunctionEntry()); // Visit statements in the function body. @@ -98,7 +98,7 @@ bool AstGraphBuilder::CreateGraph() { if (FLAG_trace) { // TODO(mstarzinger): Only traces implicit return. Node* return_value = jsgraph()->UndefinedConstant(); - NewNode(javascript()->Runtime(Runtime::kTraceExit, 1), return_value); + NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value); } // Return 'undefined' in case we can fall off the end. @@ -643,20 +643,20 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { // TODO(dcarney): should do a fast enum cache check here to skip runtime. environment()->Push(obj); Node* cache_type = ProcessArguments( - javascript()->Runtime(Runtime::kGetPropertyNamesFast, 1), 1); + javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), 1); // TODO(dcarney): these next runtime calls should be removed in favour of // a few simplified instructions. environment()->Push(obj); environment()->Push(cache_type); Node* cache_pair = - ProcessArguments(javascript()->Runtime(Runtime::kForInInit, 2), 2); + ProcessArguments(javascript()->CallRuntime(Runtime::kForInInit, 2), 2); // cache_type may have been replaced. Node* cache_array = NewNode(common()->Projection(0), cache_pair); cache_type = NewNode(common()->Projection(1), cache_pair); environment()->Push(cache_type); environment()->Push(cache_array); Node* cache_length = ProcessArguments( - javascript()->Runtime(Runtime::kForInCacheArrayLength, 2), 2); + javascript()->CallRuntime(Runtime::kForInCacheArrayLength, 2), 2); { // TODO(dcarney): this check is actually supposed to be for the // empty enum case only. @@ -692,8 +692,8 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { environment()->Push(cache_array); environment()->Push(cache_type); environment()->Push(index); - Node* pair = - ProcessArguments(javascript()->Runtime(Runtime::kForInNext, 4), 4); + Node* pair = ProcessArguments( + javascript()->CallRuntime(Runtime::kForInNext, 4), 4); Node* value = NewNode(common()->Projection(0), pair); Node* should_filter = NewNode(common()->Projection(1), pair); environment()->Push(value); @@ -719,7 +719,7 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { // result is either the string key or Smi(0) indicating the property // is gone. Node* res = ProcessArguments( - javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 3); + javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), 3); // TODO(jarin): provide real bailout id. PrepareFrameState(res, BailoutId::None()); Node* property_missing = NewNode(javascript()->StrictEqual(), res, @@ -785,7 +785,7 @@ void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { // TODO(turbofan): Do we really need a separate reloc-info for this? - Node* node = NewNode(javascript()->Runtime(Runtime::kDebugBreak, 0)); + Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0)); PrepareFrameState(node, stmt->DebugBreakId()); } @@ -806,7 +806,7 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { Node* info = jsgraph()->Constant(shared_info); Node* pretenure = expr->pretenure() ? jsgraph()->TrueConstant() : jsgraph()->FalseConstant(); - const Operator* op = javascript()->Runtime(Runtime::kNewClosure, 3); + const Operator* op = javascript()->CallRuntime(Runtime::kNewClosure, 3); Node* value = NewNode(op, context, info, pretenure); ast_context()->ProduceValue(value); } @@ -859,7 +859,7 @@ void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { Node* pattern = jsgraph()->Constant(expr->pattern()); Node* flags = jsgraph()->Constant(expr->flags()); const Operator* op = - javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4); + javascript()->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); Node* literal = NewNode(op, literals_array, literal_index, pattern, flags); PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine()); ast_context()->ProduceValue(literal); @@ -876,7 +876,8 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* constants = jsgraph()->Constant(expr->constant_properties()); Node* flags = jsgraph()->Constant(expr->ComputeFlags()); - const Operator* op = javascript()->Runtime(Runtime::kCreateObjectLiteral, 4); + const Operator* op = + javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4); Node* literal = NewNode(op, literals_array, literal_index, constants, flags); // The object is expected on the operand stack during computation of the @@ -925,7 +926,8 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { Node* receiver = environment()->Pop(); if (property->emit_store()) { Node* strict = jsgraph()->Constant(SLOPPY); - const Operator* op = javascript()->Runtime(Runtime::kSetProperty, 4); + const Operator* op = + javascript()->CallRuntime(Runtime::kSetProperty, 4); NewNode(op, receiver, key, value, strict); } break; @@ -936,7 +938,8 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { Node* value = environment()->Pop(); Node* receiver = environment()->Pop(); if (property->emit_store()) { - const Operator* op = javascript()->Runtime(Runtime::kSetPrototype, 2); + const Operator* op = + javascript()->CallRuntime(Runtime::kSetPrototype, 2); NewNode(op, receiver, value); } break; @@ -962,14 +965,15 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { Node* name = environment()->Pop(); Node* attr = jsgraph()->Constant(NONE); const Operator* op = - javascript()->Runtime(Runtime::kDefineAccessorPropertyUnchecked, 5); + javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5); Node* call = NewNode(op, literal, name, getter, setter, attr); PrepareFrameState(call, it->first->id()); } // Transform literals that contain functions to fast properties. if (expr->has_function()) { - const Operator* op = javascript()->Runtime(Runtime::kToFastProperties, 1); + const Operator* op = + javascript()->CallRuntime(Runtime::kToFastProperties, 1); NewNode(op, literal); } @@ -987,7 +991,8 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* constants = jsgraph()->Constant(expr->constant_elements()); Node* flags = jsgraph()->Constant(expr->ComputeFlags()); - const Operator* op = javascript()->Runtime(Runtime::kCreateArrayLiteral, 4); + const Operator* op = + javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4); Node* literal = NewNode(op, literals_array, literal_index, constants, flags); // The array and the literal index are both expected on the operand stack @@ -1166,7 +1171,7 @@ void AstGraphBuilder::VisitYield(Yield* expr) { void AstGraphBuilder::VisitThrow(Throw* expr) { VisitForValue(expr->exception()); Node* exception = environment()->Pop(); - const Operator* op = javascript()->Runtime(Runtime::kThrow, 1); + const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1); Node* value = NewNode(op, exception); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); ast_context()->ProduceValue(value); @@ -1213,7 +1218,8 @@ void AstGraphBuilder::VisitCall(Call* expr) { Variable* variable = callee->AsVariableProxy()->var(); DCHECK(variable->location() == Variable::LOOKUP); Node* name = jsgraph()->Constant(variable->name()); - const Operator* op = javascript()->Runtime(Runtime::kLoadLookupSlot, 2); + const Operator* op = + javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2); Node* pair = NewNode(op, current_context(), name); callee_value = NewNode(common()->Projection(0), pair); receiver_value = NewNode(common()->Projection(1), pair); @@ -1278,7 +1284,7 @@ void AstGraphBuilder::VisitCall(Call* expr) { Node* strict = jsgraph()->Constant(strict_mode()); Node* position = jsgraph()->Constant(info()->scope()->start_position()); const Operator* op = - javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 5); + javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); Node* pair = NewNode(op, callee, source, receiver, strict, position); PrepareFrameState(pair, expr->EvalOrLookupId(), OutputFrameStateCombine::PokeAt(arg_count + 1)); @@ -1291,7 +1297,7 @@ void AstGraphBuilder::VisitCall(Call* expr) { } // Create node to perform the function call. - const Operator* call = javascript()->Call(args->length() + 2, flags); + const Operator* call = javascript()->CallFunction(args->length() + 2, flags); Node* value = ProcessArguments(call, args->length() + 2); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); ast_context()->ProduceValue(value); @@ -1306,7 +1312,7 @@ void AstGraphBuilder::VisitCallNew(CallNew* expr) { VisitForValues(args); // Create node to perform the construct call. - const Operator* call = javascript()->CallNew(args->length() + 1); + const Operator* call = javascript()->CallConstruct(args->length() + 1); Node* value = ProcessArguments(call, args->length() + 1); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); ast_context()->ProduceValue(value); @@ -1334,7 +1340,7 @@ void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) { VisitForValues(args); // Create node to perform the JS runtime call. - const Operator* call = javascript()->Call(args->length() + 2, flags); + const Operator* call = javascript()->CallFunction(args->length() + 2, flags); Node* value = ProcessArguments(call, args->length() + 2); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); ast_context()->ProduceValue(value); @@ -1357,7 +1363,7 @@ void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) { // Create node to perform the runtime call. Runtime::FunctionId functionId = function->function_id; - const Operator* call = javascript()->Runtime(functionId, args->length()); + const Operator* call = javascript()->CallRuntime(functionId, args->length()); Node* value = ProcessArguments(call, args->length()); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); ast_context()->ProduceValue(value); @@ -1571,7 +1577,7 @@ void AstGraphBuilder::VisitDeclarations(ZoneList* declarations) { DeclareGlobalsStrictMode::encode(strict_mode()); Node* flags = jsgraph()->Constant(encoded_flags); Node* pairs = jsgraph()->Constant(data); - const Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3); + const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals, 3); NewNode(op, current_context(), pairs, flags); globals()->Rewind(0); } @@ -1680,6 +1686,11 @@ void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { } +StrictMode AstGraphBuilder::strict_mode() const { + return info()->strict_mode(); +} + + Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) { DCHECK(environment()->stack_height() >= arity); Node** all = info()->zone()->NewArray(arity); @@ -1724,7 +1735,7 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) { // Allocate and initialize a new arguments object. Node* callee = GetFunctionClosure(); - const Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1); + const Operator* op = javascript()->CallRuntime(Runtime::kNewArguments, 1); Node* object = NewNode(op, callee); // Assign the object to the arguments variable. @@ -1831,7 +1842,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, (contextual_mode == CONTEXTUAL) ? Runtime::kLoadLookupSlot : Runtime::kLoadLookupSlotNoReferenceError; - const Operator* op = javascript()->Runtime(function_id, 2); + const Operator* op = javascript()->CallRuntime(function_id, 2); Node* pair = NewNode(op, current_context(), name); PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1)); return NewNode(common()->Projection(0), pair); @@ -1864,7 +1875,8 @@ Node* AstGraphBuilder::BuildVariableDelete( case Variable::LOOKUP: { // Dynamic lookup of context variable (anywhere in the chain). Node* name = jsgraph()->Constant(variable->name()); - const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2); + const Operator* op = + javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2); Node* result = NewNode(op, current_context(), name); PrepareFrameState(result, bailout_id, state_combine); return result; @@ -1950,7 +1962,8 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value, Node* strict = jsgraph()->Constant(strict_mode()); // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for // initializations of const declarations. - const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4); + const Operator* op = + javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4); Node* store = NewNode(op, value, current_context(), name, strict); PrepareFrameState(store, bailout_id); return store; @@ -1995,7 +2008,8 @@ Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable, BailoutId bailout_id) { // TODO(mstarzinger): Should be unified with the VisitThrow implementation. Node* variable_name = jsgraph()->Constant(variable->name()); - const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1); + const Operator* op = + javascript()->CallRuntime(Runtime::kThrowReferenceError, 1); Node* call = NewNode(op, variable_name); PrepareFrameState(call, bailout_id); return call; diff --git a/src/compiler/ast-graph-builder.h b/src/compiler/ast-graph-builder.h index b622355..feded98 100644 --- a/src/compiler/ast-graph-builder.h +++ b/src/compiler/ast-graph-builder.h @@ -131,8 +131,8 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { SetOncePointer function_closure_; SetOncePointer function_context_; - CompilationInfo* info() { return info_; } - StrictMode strict_mode() { return info()->strict_mode(); } + CompilationInfo* info() const { return info_; } + inline StrictMode strict_mode() const; JSGraph* jsgraph() { return jsgraph_; } JSOperatorBuilder* javascript() { return jsgraph_->javascript(); } ZoneList >* globals() { return &globals_; } diff --git a/src/compiler/change-lowering.cc b/src/compiler/change-lowering.cc index b13db4c..5b66d55 100644 --- a/src/compiler/change-lowering.cc +++ b/src/compiler/change-lowering.cc @@ -3,9 +3,10 @@ // found in the LICENSE file. #include "src/compiler/change-lowering.h" -#include "src/compiler/machine-operator.h" #include "src/compiler/js-graph.h" +#include "src/compiler/linkage.h" +#include "src/compiler/machine-operator.h" namespace v8 { namespace internal { diff --git a/src/compiler/compiler.gyp b/src/compiler/compiler.gyp index ec5ec28..2a831d8 100644 --- a/src/compiler/compiler.gyp +++ b/src/compiler/compiler.gyp @@ -27,6 +27,7 @@ 'instruction-selector-unittest.cc', 'instruction-selector-unittest.h', 'js-builtin-reducer-unittest.cc', + 'js-operator-unittest.cc', 'machine-operator-reducer-unittest.cc', 'machine-operator-unittest.cc', 'simplified-operator-reducer-unittest.cc', diff --git a/src/compiler/js-builtin-reducer-unittest.cc b/src/compiler/js-builtin-reducer-unittest.cc index 5177d8d..22311a6 100644 --- a/src/compiler/js-builtin-reducer-unittest.cc +++ b/src/compiler/js-builtin-reducer-unittest.cc @@ -69,8 +69,9 @@ TEST_F(JSBuiltinReducerTest, MathAbs) { TRACED_FOREACH(Type*, t0, kNumberTypes) { Node* p0 = Parameter(t0, 0); Node* fun = HeapConstant(Unique::CreateUninitialized(f)); - Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); + Node* call = + graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), + fun, UndefinedConstant(), p0); Reduction r = Reduce(call); if (t0->Is(Type::Unsigned32())) { @@ -102,8 +103,9 @@ TEST_F(JSBuiltinReducerTest, MathSqrt) { TRACED_FOREACH(Type*, t0, kNumberTypes) { Node* p0 = Parameter(t0, 0); Node* fun = HeapConstant(Unique::CreateUninitialized(f)); - Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); + Node* call = + graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), + fun, UndefinedConstant(), p0); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); @@ -120,8 +122,9 @@ TEST_F(JSBuiltinReducerTest, MathMax0) { Handle f(isolate()->context()->math_max_fun()); Node* fun = HeapConstant(Unique::CreateUninitialized(f)); - Node* call = graph()->NewNode(javascript()->Call(2, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant()); + Node* call = + graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS), + fun, UndefinedConstant()); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); @@ -135,8 +138,9 @@ TEST_F(JSBuiltinReducerTest, MathMax1) { TRACED_FOREACH(Type*, t0, kNumberTypes) { Node* p0 = Parameter(t0, 0); Node* fun = HeapConstant(Unique::CreateUninitialized(f)); - Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); + Node* call = + graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), + fun, UndefinedConstant(), p0); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); @@ -153,9 +157,9 @@ TEST_F(JSBuiltinReducerTest, MathMax2) { Node* p0 = Parameter(t0, 0); Node* p1 = Parameter(t1, 1); Node* fun = HeapConstant(Unique::CreateUninitialized(f)); - Node* call = - graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun, - UndefinedConstant(), p0, p1); + Node* call = graph()->NewNode( + javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun, + UndefinedConstant(), p0, p1); Reduction r = Reduce(call); if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) { @@ -189,9 +193,9 @@ TEST_F(JSBuiltinReducerTest, MathImul) { Node* p0 = Parameter(t0, 0); Node* p1 = Parameter(t1, 1); Node* fun = HeapConstant(Unique::CreateUninitialized(f)); - Node* call = - graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun, - UndefinedConstant(), p0, p1); + Node* call = graph()->NewNode( + javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun, + UndefinedConstant(), p0, p1); Reduction r = Reduce(call); if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) { @@ -222,8 +226,9 @@ TEST_F(JSBuiltinReducerTest, MathFround) { TRACED_FOREACH(Type*, t0, kNumberTypes) { Node* p0 = Parameter(t0, 0); Node* fun = HeapConstant(Unique::CreateUninitialized(f)); - Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); + Node* call = + graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), + fun, UndefinedConstant(), p0); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); diff --git a/src/compiler/js-context-specialization.cc b/src/compiler/js-context-specialization.cc index cd8932b..ed76f11 100644 --- a/src/compiler/js-context-specialization.cc +++ b/src/compiler/js-context-specialization.cc @@ -67,11 +67,11 @@ Reduction JSContextSpecializer::ReduceJSLoadContext(Node* node) { return Reducer::NoChange(); } - ContextAccess access = OpParameter(node); + const ContextAccess& access = ContextAccessOf(node->op()); // Find the right parent context. Context* context = *m.Value().handle(); - for (int i = access.depth(); i > 0; --i) { + for (size_t i = access.depth(); i > 0; --i) { context = context->previous(); } @@ -88,8 +88,8 @@ Reduction JSContextSpecializer::ReduceJSLoadContext(Node* node) { node->ReplaceInput(0, jsgraph_->Constant(context_handle)); return Reducer::Changed(node); } - Handle value = - Handle(context->get(access.index()), info_->isolate()); + Handle value = Handle( + context->get(static_cast(access.index())), info_->isolate()); // Even though the context slot is immutable, the context might have escaped // before the function to which it belongs has initialized the slot. @@ -115,7 +115,7 @@ Reduction JSContextSpecializer::ReduceJSStoreContext(Node* node) { return Reducer::NoChange(); } - ContextAccess access = OpParameter(node); + const ContextAccess& access = ContextAccessOf(node->op()); // The access does not have to look up a parent, nothing to fold. if (access.depth() == 0) { @@ -124,7 +124,7 @@ Reduction JSContextSpecializer::ReduceJSStoreContext(Node* node) { // Find the right parent context. Context* context = *m.Value().handle(); - for (int i = access.depth(); i > 0; --i) { + for (size_t i = access.depth(); i > 0; --i) { context = context->previous(); } diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 146185e..78ead5e 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -281,9 +281,9 @@ void JSGenericLowering::LowerJSLoadProperty(Node* node) { void JSGenericLowering::LowerJSLoadNamed(Node* node) { - LoadNamedParameters p = OpParameter(node); - Callable callable = CodeFactory::LoadIC(isolate(), p.contextual_mode); - PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name)); + const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); + Callable callable = CodeFactory::LoadIC(isolate(), p.contextual_mode()); + PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name())); ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite); } @@ -296,9 +296,9 @@ void JSGenericLowering::LowerJSStoreProperty(Node* node) { void JSGenericLowering::LowerJSStoreNamed(Node* node) { - StoreNamedParameters params = OpParameter(node); - Callable callable = CodeFactory::StoreIC(isolate(), params.strict_mode); - PatchInsertInput(node, 1, jsgraph()->HeapConstant(params.name)); + const StoreNamedParameters& p = StoreNamedParametersOf(node->op()); + Callable callable = CodeFactory::StoreIC(isolate(), p.strict_mode()); + PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name())); ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite); } @@ -330,10 +330,10 @@ void JSGenericLowering::LowerJSInstanceOf(Node* node) { void JSGenericLowering::LowerJSLoadContext(Node* node) { - ContextAccess access = OpParameter(node); + const ContextAccess& access = ContextAccessOf(node->op()); // TODO(mstarzinger): Use simplified operators instead of machine operators // here so that load/store optimization can be applied afterwards. - for (int i = 0; i < access.depth(); ++i) { + for (size_t i = 0; i < access.depth(); ++i) { node->ReplaceInput( 0, graph()->NewNode( machine()->Load(kMachAnyTagged), @@ -341,16 +341,17 @@ void JSGenericLowering::LowerJSLoadContext(Node* node) { Int32Constant(Context::SlotOffset(Context::PREVIOUS_INDEX)), NodeProperties::GetEffectInput(node))); } - node->ReplaceInput(1, Int32Constant(Context::SlotOffset(access.index()))); + node->ReplaceInput( + 1, Int32Constant(Context::SlotOffset(static_cast(access.index())))); PatchOperator(node, machine()->Load(kMachAnyTagged)); } void JSGenericLowering::LowerJSStoreContext(Node* node) { - ContextAccess access = OpParameter(node); + const ContextAccess& access = ContextAccessOf(node->op()); // TODO(mstarzinger): Use simplified operators instead of machine operators // here so that load/store optimization can be applied afterwards. - for (int i = 0; i < access.depth(); ++i) { + for (size_t i = 0; i < access.depth(); ++i) { node->ReplaceInput( 0, graph()->NewNode( machine()->Load(kMachAnyTagged), @@ -359,7 +360,8 @@ void JSGenericLowering::LowerJSStoreContext(Node* node) { NodeProperties::GetEffectInput(node))); } node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1)); - node->ReplaceInput(1, Int32Constant(Context::SlotOffset(access.index()))); + node->ReplaceInput( + 1, Int32Constant(Context::SlotOffset(static_cast(access.index())))); PatchOperator(node, machine()->Store(StoreRepresentation(kMachAnyTagged, kFullWriteBarrier))); } @@ -382,11 +384,11 @@ void JSGenericLowering::LowerJSCallConstruct(Node* node) { void JSGenericLowering::LowerJSCallFunction(Node* node) { - CallParameters p = OpParameter(node); - CallFunctionStub stub(isolate(), p.arity - 2, p.flags); + const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); + CallFunctionStub stub(isolate(), static_cast(p.arity() - 2), p.flags()); CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor(); - CallDescriptor* desc = - linkage()->GetStubCallDescriptor(d, p.arity - 1, FlagsForNode(node)); + CallDescriptor* desc = linkage()->GetStubCallDescriptor( + d, static_cast(p.arity() - 1), FlagsForNode(node)); Node* stub_code = CodeConstant(stub.GetCode()); PatchInsertInput(node, 0, stub_code); PatchOperator(node, common()->Call(desc)); @@ -394,9 +396,8 @@ void JSGenericLowering::LowerJSCallFunction(Node* node) { void JSGenericLowering::LowerJSCallRuntime(Node* node) { - Runtime::FunctionId function = OpParameter(node); - int arity = OperatorProperties::GetValueInputCount(node->op()); - ReplaceWithRuntimeCall(node, function, arity); + const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op()); + ReplaceWithRuntimeCall(node, p.id(), static_cast(p.arity())); } } // namespace compiler diff --git a/src/compiler/js-generic-lowering.h b/src/compiler/js-generic-lowering.h index 400f806..b2f46fb 100644 --- a/src/compiler/js-generic-lowering.h +++ b/src/compiler/js-generic-lowering.h @@ -5,13 +5,12 @@ #ifndef V8_COMPILER_JS_GENERIC_LOWERING_H_ #define V8_COMPILER_JS_GENERIC_LOWERING_H_ -#include "src/v8.h" - #include "src/allocation.h" #include "src/code-factory.h" #include "src/compiler/graph.h" #include "src/compiler/graph-reducer.h" #include "src/compiler/js-graph.h" +#include "src/compiler/linkage.h" #include "src/compiler/opcodes.h" namespace v8 { diff --git a/src/compiler/js-operator-unittest.cc b/src/compiler/js-operator-unittest.cc new file mode 100644 index 0000000..fda1402 --- /dev/null +++ b/src/compiler/js-operator-unittest.cc @@ -0,0 +1,152 @@ +// 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. + +#include "src/compiler/js-operator.h" +#include "src/compiler/operator-properties-inl.h" +#include "src/test/test-utils.h" + +namespace v8 { +namespace internal { +namespace compiler { + +// ----------------------------------------------------------------------------- +// Shared operators. + +namespace { + +struct SharedOperator { + const Operator* (JSOperatorBuilder::*constructor)(); + IrOpcode::Value opcode; + Operator::Properties properties; + int value_input_count; + int frame_state_input_count; + int effect_input_count; + int control_input_count; + int value_output_count; + int effect_output_count; +}; + + +std::ostream& operator<<(std::ostream& os, const SharedOperator& sop) { + return os << IrOpcode::Mnemonic(sop.opcode); +} + + +const SharedOperator kSharedOperators[] = { +#define SHARED(Name, properties, value_input_count, frame_state_input_count, \ + effect_input_count, control_input_count, value_output_count, \ + effect_output_count) \ + { \ + &JSOperatorBuilder::Name, IrOpcode::kJS##Name, properties, \ + value_input_count, frame_state_input_count, effect_input_count, \ + control_input_count, value_output_count, effect_output_count \ + } + SHARED(Equal, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(StrictEqual, Operator::kPure, 2, 0, 0, 0, 1, 0), + SHARED(StrictNotEqual, Operator::kPure, 2, 0, 0, 0, 1, 0), + SHARED(LessThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(BitwiseOr, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(BitwiseXor, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(BitwiseAnd, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(ShiftLeft, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(ShiftRight, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(Add, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(Subtract, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(Multiply, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(Divide, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(Modulus, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(UnaryNot, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), + SHARED(ToBoolean, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), + SHARED(ToNumber, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), + SHARED(ToString, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), + SHARED(ToName, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), + SHARED(ToObject, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), + SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), + SHARED(Create, Operator::kEliminatable, 0, 0, 1, 0, 1, 1), + SHARED(LoadProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), + SHARED(HasProperty, Operator::kNoProperties, 2, 0, 1, 1, 1, 1), + SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0), + SHARED(InstanceOf, Operator::kNoProperties, 2, 0, 1, 1, 1, 1), + SHARED(Debugger, Operator::kNoProperties, 0, 0, 1, 1, 0, 1), + SHARED(CreateFunctionContext, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), + SHARED(CreateWithContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1), + SHARED(CreateBlockContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1), + SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1), + SHARED(CreateGlobalContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1) +#undef SHARED +}; + +} // namespace + + +class JSSharedOperatorTest + : public TestWithZone, + public ::testing::WithParamInterface {}; + + +TEST_P(JSSharedOperatorTest, InstancesAreGloballyShared) { + const SharedOperator& sop = GetParam(); + JSOperatorBuilder javascript1(zone()); + JSOperatorBuilder javascript2(zone()); + EXPECT_EQ((javascript1.*sop.constructor)(), (javascript2.*sop.constructor)()); +} + + +TEST_P(JSSharedOperatorTest, NumberOfInputsAndOutputs) { + JSOperatorBuilder javascript(zone()); + const SharedOperator& sop = GetParam(); + const Operator* op = (javascript.*sop.constructor)(); + + const int context_input_count = 1; + // TODO(jarin): Get rid of this hack. + const int frame_state_input_count = + FLAG_turbo_deoptimization ? sop.frame_state_input_count : 0; + EXPECT_EQ(sop.value_input_count, OperatorProperties::GetValueInputCount(op)); + EXPECT_EQ(context_input_count, OperatorProperties::GetContextInputCount(op)); + EXPECT_EQ(frame_state_input_count, + OperatorProperties::GetFrameStateInputCount(op)); + EXPECT_EQ(sop.effect_input_count, + OperatorProperties::GetEffectInputCount(op)); + EXPECT_EQ(sop.control_input_count, + OperatorProperties::GetControlInputCount(op)); + EXPECT_EQ(sop.value_input_count + context_input_count + + frame_state_input_count + sop.effect_input_count + + sop.control_input_count, + OperatorProperties::GetTotalInputCount(op)); + + EXPECT_EQ(sop.value_output_count, + OperatorProperties::GetValueOutputCount(op)); + EXPECT_EQ(sop.effect_output_count, + OperatorProperties::GetEffectOutputCount(op)); + EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op)); +} + + +TEST_P(JSSharedOperatorTest, OpcodeIsCorrect) { + JSOperatorBuilder javascript(zone()); + const SharedOperator& sop = GetParam(); + const Operator* op = (javascript.*sop.constructor)(); + EXPECT_EQ(sop.opcode, op->opcode()); +} + + +TEST_P(JSSharedOperatorTest, Properties) { + JSOperatorBuilder javascript(zone()); + const SharedOperator& sop = GetParam(); + const Operator* op = (javascript.*sop.constructor)(); + EXPECT_EQ(sop.properties, op->properties()); +} + + +INSTANTIATE_TEST_CASE_P(JSOperatorTest, JSSharedOperatorTest, + ::testing::ValuesIn(kSharedOperators)); + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc new file mode 100644 index 0000000..a10bcda --- /dev/null +++ b/src/compiler/js-operator.cc @@ -0,0 +1,251 @@ +// 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. + +#include "src/compiler/js-operator.h" + +#include + +#include "src/base/lazy-instance.h" +#include "src/compiler/opcodes.h" +#include "src/compiler/operator.h" + +namespace v8 { +namespace internal { +namespace compiler { + +const CallFunctionParameters& CallFunctionParametersOf(const Operator* op) { + DCHECK_EQ(IrOpcode::kJSCallFunction, op->opcode()); + return OpParameter(op); +} + + +const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op) { + DCHECK_EQ(IrOpcode::kJSCallRuntime, op->opcode()); + return OpParameter(op); +} + + +ContextAccess::ContextAccess(size_t depth, size_t index, bool immutable) + : immutable_(immutable), + depth_(static_cast(depth)), + index_(static_cast(index)) { + DCHECK(depth <= std::numeric_limits::max()); + DCHECK(index <= std::numeric_limits::max()); +} + + +bool operator==(const ContextAccess& lhs, const ContextAccess& rhs) { + return lhs.depth() == rhs.depth() && lhs.index() == rhs.index() && + lhs.immutable() == rhs.immutable(); +} + + +bool operator!=(const ContextAccess& lhs, const ContextAccess& rhs) { + return !(lhs == rhs); +} + + +const ContextAccess& ContextAccessOf(const Operator* op) { + DCHECK(op->opcode() == IrOpcode::kJSLoadContext || + op->opcode() == IrOpcode::kJSStoreContext); + return OpParameter(op); +} + + +const LoadNamedParameters& LoadNamedParametersOf(const Operator* op) { + DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode()); + return OpParameter(op); +} + + +const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) { + DCHECK_EQ(IrOpcode::kJSStoreNamed, op->opcode()); + return OpParameter(op); +} + + +// Specialization for static parameters of type {ContextAccess}. +template <> +struct StaticParameterTraits { + static std::ostream& PrintTo(std::ostream& os, const ContextAccess& access) { + return os << access.depth() << "," << access.index() + << (access.immutable() ? ",imm" : ""); + } + static int HashCode(const ContextAccess& access) { + return static_cast((access.depth() << 16) | (access.index() & 0xffff)); + } + static bool Equals(const ContextAccess& lhs, const ContextAccess& rhs) { + return lhs == rhs; + } +}; + + +// Specialization for static parameters of type {Runtime::FunctionId}. +template <> +struct StaticParameterTraits { + static std::ostream& PrintTo(std::ostream& os, Runtime::FunctionId val) { + const Runtime::Function* f = Runtime::FunctionForId(val); + return os << (f->name ? f->name : "?Runtime?"); + } + static int HashCode(Runtime::FunctionId val) { return static_cast(val); } + static bool Equals(Runtime::FunctionId a, Runtime::FunctionId b) { + return a == b; + } +}; + + +#define SHARED_OP_LIST(V) \ + V(Equal, Operator::kNoProperties, 2, 1) \ + V(NotEqual, Operator::kNoProperties, 2, 1) \ + V(StrictEqual, Operator::kPure, 2, 1) \ + V(StrictNotEqual, Operator::kPure, 2, 1) \ + V(LessThan, Operator::kNoProperties, 2, 1) \ + V(GreaterThan, Operator::kNoProperties, 2, 1) \ + V(LessThanOrEqual, Operator::kNoProperties, 2, 1) \ + V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1) \ + V(BitwiseOr, Operator::kNoProperties, 2, 1) \ + V(BitwiseXor, Operator::kNoProperties, 2, 1) \ + V(BitwiseAnd, Operator::kNoProperties, 2, 1) \ + V(ShiftLeft, Operator::kNoProperties, 2, 1) \ + V(ShiftRight, Operator::kNoProperties, 2, 1) \ + V(ShiftRightLogical, Operator::kNoProperties, 2, 1) \ + V(Add, Operator::kNoProperties, 2, 1) \ + V(Subtract, Operator::kNoProperties, 2, 1) \ + V(Multiply, Operator::kNoProperties, 2, 1) \ + V(Divide, Operator::kNoProperties, 2, 1) \ + V(Modulus, Operator::kNoProperties, 2, 1) \ + V(UnaryNot, Operator::kNoProperties, 1, 1) \ + V(ToBoolean, Operator::kNoProperties, 1, 1) \ + V(ToNumber, Operator::kNoProperties, 1, 1) \ + V(ToString, Operator::kNoProperties, 1, 1) \ + V(ToName, Operator::kNoProperties, 1, 1) \ + V(ToObject, Operator::kNoProperties, 1, 1) \ + V(Yield, Operator::kNoProperties, 1, 1) \ + V(Create, Operator::kEliminatable, 0, 1) \ + V(LoadProperty, Operator::kNoProperties, 2, 1) \ + V(HasProperty, Operator::kNoProperties, 2, 1) \ + V(TypeOf, Operator::kPure, 1, 1) \ + V(InstanceOf, Operator::kNoProperties, 2, 1) \ + V(Debugger, Operator::kNoProperties, 0, 0) \ + V(CreateFunctionContext, Operator::kNoProperties, 1, 1) \ + V(CreateWithContext, Operator::kNoProperties, 2, 1) \ + V(CreateBlockContext, Operator::kNoProperties, 2, 1) \ + V(CreateModuleContext, Operator::kNoProperties, 2, 1) \ + V(CreateGlobalContext, Operator::kNoProperties, 2, 1) + + +struct JSOperatorBuilderImpl FINAL { +#define SHARED(Name, properties, value_input_count, value_output_count) \ + struct Name##Operator FINAL : public SimpleOperator { \ + Name##Operator() \ + : SimpleOperator(IrOpcode::kJS##Name, properties, value_input_count, \ + value_output_count, "JS" #Name) {} \ + }; \ + Name##Operator k##Name##Operator; + SHARED_OP_LIST(SHARED) +#undef SHARED +}; + + +static base::LazyInstance::type kImpl = + LAZY_INSTANCE_INITIALIZER; + + +JSOperatorBuilder::JSOperatorBuilder(Zone* zone) + : impl_(kImpl.Get()), zone_(zone) {} + + +#define SHARED(Name, properties, value_input_count, value_output_count) \ + const Operator* JSOperatorBuilder::Name() { return &impl_.k##Name##Operator; } +SHARED_OP_LIST(SHARED) +#undef SHARED + + +const Operator* JSOperatorBuilder::CallFunction(size_t arity, + CallFunctionFlags flags) { + CallFunctionParameters parameters(arity, flags); + return new (zone()) Operator1( + IrOpcode::kJSCallFunction, Operator::kNoProperties, + static_cast(parameters.arity()), 1, "JSCallFunction", parameters); +} + + +const Operator* JSOperatorBuilder::CallRuntime(Runtime::FunctionId id, + size_t arity) { + CallRuntimeParameters parameters(id, arity); + const Runtime::Function* f = Runtime::FunctionForId(parameters.id()); + int arguments = static_cast(parameters.arity()); + DCHECK(f->nargs == -1 || f->nargs == arguments); + return new (zone()) Operator1( + IrOpcode::kJSCallRuntime, Operator::kNoProperties, arguments, + f->result_size, "JSCallRuntime", parameters); +} + + +const Operator* JSOperatorBuilder::CallConstruct(int arguments) { + return new (zone()) + Operator1(IrOpcode::kJSCallConstruct, Operator::kNoProperties, + arguments, 1, "JSCallConstruct", arguments); +} + + +const Operator* JSOperatorBuilder::LoadNamed(const Unique& name, + ContextualMode contextual_mode) { + LoadNamedParameters parameters(name, contextual_mode); + return new (zone()) Operator1( + IrOpcode::kJSLoadNamed, Operator::kNoProperties, 1, 1, "JSLoadNamed", + parameters); +} + + +const Operator* JSOperatorBuilder::StoreProperty(StrictMode strict_mode) { + return new (zone()) + Operator1(IrOpcode::kJSStoreProperty, Operator::kNoProperties, + 3, 0, "JSStoreProperty", strict_mode); +} + + +const Operator* JSOperatorBuilder::StoreNamed(StrictMode strict_mode, + const Unique& name) { + StoreNamedParameters parameters(strict_mode, name); + return new (zone()) Operator1( + IrOpcode::kJSStoreNamed, Operator::kNoProperties, 2, 0, "JSStoreNamed", + parameters); +} + + +const Operator* JSOperatorBuilder::DeleteProperty(StrictMode strict_mode) { + return new (zone()) Operator1(IrOpcode::kJSDeleteProperty, + Operator::kNoProperties, 2, 1, + "JSDeleteProperty", strict_mode); +} + + +const Operator* JSOperatorBuilder::LoadContext(size_t depth, size_t index, + bool immutable) { + ContextAccess access(depth, index, immutable); + return new (zone()) Operator1( + IrOpcode::kJSLoadContext, Operator::kEliminatable | Operator::kNoWrite, 1, + 1, "JSLoadContext", access); +} + + +const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) { + ContextAccess access(depth, index, false); + return new (zone()) Operator1(IrOpcode::kJSStoreContext, + Operator::kNoProperties, 2, 0, + "JSStoreContext", access); +} + + +const Operator* JSOperatorBuilder::CreateCatchContext( + const Unique& name) { + return new (zone()) Operator1 >( + IrOpcode::kJSCreateCatchContext, Operator::kNoProperties, 1, 1, + "JSCreateCatchContext", name); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h index 5cf6d53..909d7f2 100644 --- a/src/compiler/js-operator.h +++ b/src/compiler/js-operator.h @@ -5,28 +5,63 @@ #ifndef V8_COMPILER_JS_OPERATOR_H_ #define V8_COMPILER_JS_OPERATOR_H_ -#include "src/compiler/linkage.h" -#include "src/compiler/opcodes.h" -#include "src/compiler/operator.h" +#include "src/runtime/runtime.h" #include "src/unique.h" -#include "src/zone.h" namespace v8 { namespace internal { namespace compiler { +// Forward declarations. +class Operator; +struct JSOperatorBuilderImpl; + + +// Defines the arity and the call flags for a JavaScript function call. This is +// used as a parameter by JSCallFunction operators. +class CallFunctionParameters FINAL { + public: + CallFunctionParameters(size_t arity, CallFunctionFlags flags) + : arity_(arity), flags_(flags) {} + + size_t arity() const { return arity_; } + CallFunctionFlags flags() const { return flags_; } + + private: + const size_t arity_; + const CallFunctionFlags flags_; +}; + +const CallFunctionParameters& CallFunctionParametersOf(const Operator* op); + + +// Defines the arity and the ID for a runtime function call. This is used as a +// parameter by JSCallRuntime operators. +class CallRuntimeParameters FINAL { + public: + CallRuntimeParameters(Runtime::FunctionId id, size_t arity) + : id_(id), arity_(arity) {} + + Runtime::FunctionId id() const { return id_; } + size_t arity() const { return arity_; } + + private: + const Runtime::FunctionId id_; + const size_t arity_; +}; + +const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op); + + // Defines the location of a context slot relative to a specific scope. This is // used as a parameter by JSLoadContext and JSStoreContext operators and allows // accessing a context-allocated variable without keeping track of the scope. -class ContextAccess { +class ContextAccess FINAL { public: - ContextAccess(int depth, int index, bool immutable) - : immutable_(immutable), depth_(depth), index_(index) { - DCHECK(0 <= depth && depth <= kMaxUInt16); - DCHECK(0 <= index && static_cast(index) <= kMaxUInt32); - } - int depth() const { return depth_; } - int index() const { return index_; } + ContextAccess(size_t depth, size_t index, bool immutable); + + size_t depth() const { return depth_; } + size_t index() const { return index_; } bool immutable() const { return immutable_; } private: @@ -37,194 +72,121 @@ class ContextAccess { const uint32_t index_; }; +bool operator==(const ContextAccess& lhs, const ContextAccess& rhs); +bool operator!=(const ContextAccess& lhs, const ContextAccess& rhs); + +const ContextAccess& ContextAccessOf(const Operator* op); + + // Defines the property being loaded from an object by a named load. This is // used as a parameter by JSLoadNamed operators. -struct LoadNamedParameters { - Unique name; - ContextualMode contextual_mode; -}; +class LoadNamedParameters FINAL { + public: + LoadNamedParameters(const Unique& name, ContextualMode contextual_mode) + : name_(name), contextual_mode_(contextual_mode) {} -// Defines the arity and the call flags for a JavaScript function call. This is -// used as a parameter by JSCall operators. -struct CallParameters { - int arity; - CallFunctionFlags flags; + const Unique& name() const { return name_; } + ContextualMode contextual_mode() const { return contextual_mode_; } + + private: + const Unique name_; + const ContextualMode contextual_mode_; }; +const LoadNamedParameters& LoadNamedParametersOf(const Operator* op); + + // Defines the property being stored to an object by a named store. This is // used as a parameter by JSStoreNamed operators. -struct StoreNamedParameters { - StrictMode strict_mode; - Unique name; +class StoreNamedParameters FINAL { + public: + StoreNamedParameters(StrictMode strict_mode, const Unique& name) + : strict_mode_(strict_mode), name_(name) {} + + StrictMode strict_mode() const { return strict_mode_; } + const Unique& name() const { return name_; } + + private: + const StrictMode strict_mode_; + const Unique name_; }; +const StoreNamedParameters& StoreNamedParametersOf(const Operator* op); + + // Interface for building JavaScript-level operators, e.g. directly from the // AST. Most operators have no parameters, thus can be globally shared for all // graphs. -class JSOperatorBuilder { +class JSOperatorBuilder FINAL { public: - explicit JSOperatorBuilder(Zone* zone) : zone_(zone) {} - -#define SIMPLE(name, properties, inputs, outputs) \ - return new (zone_) \ - SimpleOperator(IrOpcode::k##name, properties, inputs, outputs, #name); - -#define NOPROPS(name, inputs, outputs) \ - SIMPLE(name, Operator::kNoProperties, inputs, outputs) - -#define OP1(name, ptype, pname, properties, inputs, outputs) \ - return new (zone_) Operator1(IrOpcode::k##name, properties, inputs, \ - outputs, #name, pname) - -#define BINOP(name) NOPROPS(name, 2, 1) -#define UNOP(name) NOPROPS(name, 1, 1) - -#define PURE_BINOP(name) SIMPLE(name, Operator::kPure, 2, 1) - - const Operator* Equal() { BINOP(JSEqual); } - const Operator* NotEqual() { BINOP(JSNotEqual); } - const Operator* StrictEqual() { PURE_BINOP(JSStrictEqual); } - const Operator* StrictNotEqual() { PURE_BINOP(JSStrictNotEqual); } - const Operator* LessThan() { BINOP(JSLessThan); } - const Operator* GreaterThan() { BINOP(JSGreaterThan); } - const Operator* LessThanOrEqual() { BINOP(JSLessThanOrEqual); } - const Operator* GreaterThanOrEqual() { BINOP(JSGreaterThanOrEqual); } - const Operator* BitwiseOr() { BINOP(JSBitwiseOr); } - const Operator* BitwiseXor() { BINOP(JSBitwiseXor); } - const Operator* BitwiseAnd() { BINOP(JSBitwiseAnd); } - const Operator* ShiftLeft() { BINOP(JSShiftLeft); } - const Operator* ShiftRight() { BINOP(JSShiftRight); } - const Operator* ShiftRightLogical() { BINOP(JSShiftRightLogical); } - const Operator* Add() { BINOP(JSAdd); } - const Operator* Subtract() { BINOP(JSSubtract); } - const Operator* Multiply() { BINOP(JSMultiply); } - const Operator* Divide() { BINOP(JSDivide); } - const Operator* Modulus() { BINOP(JSModulus); } - - const Operator* UnaryNot() { UNOP(JSUnaryNot); } - const Operator* ToBoolean() { UNOP(JSToBoolean); } - const Operator* ToNumber() { UNOP(JSToNumber); } - const Operator* ToString() { UNOP(JSToString); } - const Operator* ToName() { UNOP(JSToName); } - const Operator* ToObject() { UNOP(JSToObject); } - const Operator* Yield() { UNOP(JSYield); } - - const Operator* Create() { SIMPLE(JSCreate, Operator::kEliminatable, 0, 1); } - - const Operator* Call(int arguments, CallFunctionFlags flags) { - CallParameters parameters = {arguments, flags}; - OP1(JSCallFunction, CallParameters, parameters, Operator::kNoProperties, - arguments, 1); - } - - const Operator* CallNew(int arguments) { - return new (zone_) - Operator1(IrOpcode::kJSCallConstruct, Operator::kNoProperties, - arguments, 1, "JSCallConstruct", arguments); - } - - const Operator* LoadProperty() { BINOP(JSLoadProperty); } - const Operator* LoadNamed(Unique name, - ContextualMode contextual_mode = NOT_CONTEXTUAL) { - LoadNamedParameters parameters = {name, contextual_mode}; - OP1(JSLoadNamed, LoadNamedParameters, parameters, Operator::kNoProperties, - 1, 1); - } - - const Operator* StoreProperty(StrictMode strict_mode) { - OP1(JSStoreProperty, StrictMode, strict_mode, Operator::kNoProperties, 3, - 0); - } - - const Operator* StoreNamed(StrictMode strict_mode, Unique name) { - StoreNamedParameters parameters = {strict_mode, name}; - OP1(JSStoreNamed, StoreNamedParameters, parameters, Operator::kNoProperties, - 2, 0); - } - - const Operator* DeleteProperty(StrictMode strict_mode) { - OP1(JSDeleteProperty, StrictMode, strict_mode, Operator::kNoProperties, 2, - 1); - } - - const Operator* HasProperty() { NOPROPS(JSHasProperty, 2, 1); } - - const Operator* LoadContext(uint16_t depth, uint32_t index, bool immutable) { - ContextAccess access(depth, index, immutable); - OP1(JSLoadContext, ContextAccess, access, - Operator::kEliminatable | Operator::kNoWrite, 1, 1); - } - const Operator* StoreContext(uint16_t depth, uint32_t index) { - ContextAccess access(depth, index, false); - OP1(JSStoreContext, ContextAccess, access, Operator::kNoProperties, 2, 0); - } - - const Operator* TypeOf() { SIMPLE(JSTypeOf, Operator::kPure, 1, 1); } - const Operator* InstanceOf() { NOPROPS(JSInstanceOf, 2, 1); } - const Operator* Debugger() { NOPROPS(JSDebugger, 0, 0); } + explicit JSOperatorBuilder(Zone* zone); + + const Operator* Equal(); + const Operator* NotEqual(); + const Operator* StrictEqual(); + const Operator* StrictNotEqual(); + const Operator* LessThan(); + const Operator* GreaterThan(); + const Operator* LessThanOrEqual(); + const Operator* GreaterThanOrEqual(); + const Operator* BitwiseOr(); + const Operator* BitwiseXor(); + const Operator* BitwiseAnd(); + const Operator* ShiftLeft(); + const Operator* ShiftRight(); + const Operator* ShiftRightLogical(); + const Operator* Add(); + const Operator* Subtract(); + const Operator* Multiply(); + const Operator* Divide(); + const Operator* Modulus(); + + const Operator* UnaryNot(); + const Operator* ToBoolean(); + const Operator* ToNumber(); + const Operator* ToString(); + const Operator* ToName(); + const Operator* ToObject(); + const Operator* Yield(); + + const Operator* Create(); + + const Operator* CallFunction(size_t arity, CallFunctionFlags flags); + const Operator* CallRuntime(Runtime::FunctionId id, size_t arity); + + const Operator* CallConstruct(int arguments); + + const Operator* LoadProperty(); + const Operator* LoadNamed(const Unique& name, + ContextualMode contextual_mode = NOT_CONTEXTUAL); + + const Operator* StoreProperty(StrictMode strict_mode); + const Operator* StoreNamed(StrictMode strict_mode, const Unique& name); + + const Operator* DeleteProperty(StrictMode strict_mode); + + const Operator* HasProperty(); + + const Operator* LoadContext(size_t depth, size_t index, bool immutable); + const Operator* StoreContext(size_t depth, size_t index); + + const Operator* TypeOf(); + const Operator* InstanceOf(); + const Operator* Debugger(); // TODO(titzer): nail down the static parts of each of these context flavors. - const Operator* CreateFunctionContext() { - NOPROPS(JSCreateFunctionContext, 1, 1); - } - const Operator* CreateCatchContext(Unique name) { - OP1(JSCreateCatchContext, Unique, name, Operator::kNoProperties, 1, - 1); - } - const Operator* CreateWithContext() { NOPROPS(JSCreateWithContext, 2, 1); } - const Operator* CreateBlockContext() { NOPROPS(JSCreateBlockContext, 2, 1); } - const Operator* CreateModuleContext() { - NOPROPS(JSCreateModuleContext, 2, 1); - } - const Operator* CreateGlobalContext() { - NOPROPS(JSCreateGlobalContext, 2, 1); - } - - const Operator* Runtime(Runtime::FunctionId function, int arguments) { - const Runtime::Function* f = Runtime::FunctionForId(function); - DCHECK(f->nargs == -1 || f->nargs == arguments); - OP1(JSCallRuntime, Runtime::FunctionId, function, Operator::kNoProperties, - arguments, f->result_size); - } - -#undef SIMPLE -#undef NOPROPS -#undef OP1 -#undef BINOP -#undef UNOP + const Operator* CreateFunctionContext(); + const Operator* CreateCatchContext(const Unique& name); + const Operator* CreateWithContext(); + const Operator* CreateBlockContext(); + const Operator* CreateModuleContext(); + const Operator* CreateGlobalContext(); private: - Zone* zone_; -}; - -// Specialization for static parameters of type {ContextAccess}. -template <> -struct StaticParameterTraits { - static std::ostream& PrintTo(std::ostream& os, ContextAccess val) { // NOLINT - return os << val.depth() << "," << val.index() - << (val.immutable() ? ",imm" : ""); - } - static int HashCode(ContextAccess val) { - return (val.depth() << 16) | (val.index() & 0xffff); - } - static bool Equals(ContextAccess a, ContextAccess b) { - return a.immutable() == b.immutable() && a.depth() == b.depth() && - a.index() == b.index(); - } -}; + Zone* zone() const { return zone_; } -// Specialization for static parameters of type {Runtime::FunctionId}. -template <> -struct StaticParameterTraits { - static std::ostream& PrintTo(std::ostream& os, - Runtime::FunctionId val) { // NOLINT - const Runtime::Function* f = Runtime::FunctionForId(val); - return os << (f->name ? f->name : "?Runtime?"); - } - static int HashCode(Runtime::FunctionId val) { return static_cast(val); } - static bool Equals(Runtime::FunctionId a, Runtime::FunctionId b) { - return a == b; - } + const JSOperatorBuilderImpl& impl_; + Zone* const zone_; }; } // namespace compiler diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc index fa31d05..d6b3ff2 100644 --- a/src/compiler/machine-operator-reducer.cc +++ b/src/compiler/machine-operator-reducer.cc @@ -5,6 +5,7 @@ #include "src/compiler/machine-operator-reducer.h" #include "src/base/bits.h" +#include "src/codegen.h" #include "src/compiler/generic-node-inl.h" #include "src/compiler/graph.h" #include "src/compiler/js-graph.h" diff --git a/src/compiler/operator-properties-inl.h b/src/compiler/operator-properties-inl.h index cb598aa..51d43d4 100644 --- a/src/compiler/operator-properties-inl.h +++ b/src/compiler/operator-properties-inl.h @@ -7,6 +7,7 @@ #include "src/compiler/common-operator.h" #include "src/compiler/js-operator.h" +#include "src/compiler/linkage.h" #include "src/compiler/opcodes.h" #include "src/compiler/operator-properties.h" @@ -40,8 +41,8 @@ inline bool OperatorProperties::HasFrameStateInput(const Operator* op) { case IrOpcode::kFrameState: return true; case IrOpcode::kJSCallRuntime: { - Runtime::FunctionId function = OpParameter(op); - return Linkage::NeedsFrameState(function); + const CallRuntimeParameters& p = CallRuntimeParametersOf(op); + return Linkage::NeedsFrameState(p.id()); } // Strict equality cannot lazily deoptimize. diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index b6349c9..8be542e 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -557,7 +557,7 @@ Bounds Typer::Visitor::TypeJSLoadContext(Node* node) { // bound. // TODO(rossberg): Could use scope info to fix upper bounds for constant // bindings if we know that this code is never shared. - for (int i = access.depth(); i > 0; --i) { + for (size_t i = access.depth(); i > 0; --i) { if (context_type->IsContext()) { context_type = context_type->AsContext()->Outer(); if (context_type->IsConstant()) { @@ -571,7 +571,8 @@ Bounds Typer::Visitor::TypeJSLoadContext(Node* node) { return Bounds::Unbounded(zone()); } else { Handle value = - handle(context.ToHandleChecked()->get(access.index()), isolate()); + handle(context.ToHandleChecked()->get(static_cast(access.index())), + isolate()); Type* lower = TypeConstant(value); return Bounds(lower, Type::Any(zone())); } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index da8511b..eafb19f 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -6,6 +6,7 @@ #define V8_RUNTIME_H_ #include "src/allocation.h" +#include "src/objects.h" #include "src/zone.h" namespace v8 { diff --git a/test/cctest/compiler/test-js-context-specialization.cc b/test/cctest/compiler/test-js-context-specialization.cc index 47c660a..46d6e43 100644 --- a/test/cctest/compiler/test-js-context-specialization.cc +++ b/test/cctest/compiler/test-js-context-specialization.cc @@ -95,8 +95,8 @@ TEST(ReduceJSLoadContext) { HeapObjectMatcher match(new_context_input); CHECK_EQ(*native, *match.Value().handle()); ContextAccess access = OpParameter(r.replacement()); - CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index()); - CHECK_EQ(0, access.depth()); + CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast(access.index())); + CHECK_EQ(0, static_cast(access.depth())); CHECK_EQ(false, access.immutable()); } @@ -175,8 +175,8 @@ TEST(ReduceJSStoreContext) { HeapObjectMatcher match(new_context_input); CHECK_EQ(*native, *match.Value().handle()); ContextAccess access = OpParameter(r.replacement()); - CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index()); - CHECK_EQ(0, access.depth()); + CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast(access.index())); + CHECK_EQ(0, static_cast(access.depth())); CHECK_EQ(false, access.immutable()); } } diff --git a/test/cctest/compiler/test-machine-operator-reducer.cc b/test/cctest/compiler/test-machine-operator-reducer.cc index 9a41bc5..d3b4920 100644 --- a/test/cctest/compiler/test-machine-operator-reducer.cc +++ b/test/cctest/compiler/test-machine-operator-reducer.cc @@ -5,6 +5,7 @@ #include "test/cctest/cctest.h" #include "src/base/utils/random-number-generator.h" +#include "src/codegen.h" #include "src/compiler/graph-inl.h" #include "src/compiler/js-graph.h" #include "src/compiler/machine-operator-reducer.h" diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 0d86c7d..a7ececd 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -431,6 +431,7 @@ '../../src/compiler/js-graph.h', '../../src/compiler/js-inlining.cc', '../../src/compiler/js-inlining.h', + '../../src/compiler/js-operator.cc', '../../src/compiler/js-operator.h', '../../src/compiler/js-typed-lowering.cc', '../../src/compiler/js-typed-lowering.h',