V8 Project
js-generic-lowering.cc
Go to the documentation of this file.
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/code-factory.h"
6 #include "src/code-stubs.h"
13 #include "src/unique.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18 
20  : info_(info),
21  jsgraph_(jsgraph),
22  linkage_(new (jsgraph->zone()) Linkage(info)) {}
23 
24 
25 void JSGenericLowering::PatchOperator(Node* node, const Operator* op) {
26  node->set_op(op);
27 }
28 
29 
30 void JSGenericLowering::PatchInsertInput(Node* node, int index, Node* input) {
31  node->InsertInput(zone(), index, input);
32 }
33 
34 
36  return jsgraph()->SmiConstant(immediate);
37 }
38 
39 
40 Node* JSGenericLowering::Int32Constant(int immediate) {
41  return jsgraph()->Int32Constant(immediate);
42 }
43 
44 
46  return jsgraph()->HeapConstant(code);
47 }
48 
49 
51  return jsgraph()->HeapConstant(function);
52 }
53 
54 
55 Node* JSGenericLowering::ExternalConstant(ExternalReference ref) {
56  return jsgraph()->ExternalConstant(ref);
57 }
58 
59 
60 Reduction JSGenericLowering::Reduce(Node* node) {
61  switch (node->opcode()) {
62 #define DECLARE_CASE(x) \
63  case IrOpcode::k##x: \
64  Lower##x(node); \
65  break;
66  DECLARE_CASE(Branch)
68 #undef DECLARE_CASE
69  default:
70  // Nothing to see.
71  return NoChange();
72  }
73  return Changed(node);
74 }
75 
76 
77 #define REPLACE_BINARY_OP_IC_CALL(op, token) \
78  void JSGenericLowering::Lower##op(Node* node) { \
79  ReplaceWithStubCall(node, CodeFactory::BinaryOpIC(isolate(), token), \
80  CallDescriptor::kPatchableCallSiteWithNop); \
81  }
82 REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR)
83 REPLACE_BINARY_OP_IC_CALL(JSBitwiseXor, Token::BIT_XOR)
84 REPLACE_BINARY_OP_IC_CALL(JSBitwiseAnd, Token::BIT_AND)
85 REPLACE_BINARY_OP_IC_CALL(JSShiftLeft, Token::SHL)
86 REPLACE_BINARY_OP_IC_CALL(JSShiftRight, Token::SAR)
87 REPLACE_BINARY_OP_IC_CALL(JSShiftRightLogical, Token::SHR)
92 REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
93 #undef REPLACE_BINARY_OP_IC_CALL
94 
95 
96 #define REPLACE_COMPARE_IC_CALL(op, token, pure) \
97  void JSGenericLowering::Lower##op(Node* node) { \
98  ReplaceWithCompareIC(node, token, pure); \
99  }
100 REPLACE_COMPARE_IC_CALL(JSEqual, Token::EQ, false)
101 REPLACE_COMPARE_IC_CALL(JSNotEqual, Token::NE, false)
102 REPLACE_COMPARE_IC_CALL(JSStrictEqual, Token::EQ_STRICT, true)
103 REPLACE_COMPARE_IC_CALL(JSStrictNotEqual, Token::NE_STRICT, true)
104 REPLACE_COMPARE_IC_CALL(JSLessThan, Token::LT, false)
105 REPLACE_COMPARE_IC_CALL(JSGreaterThan, Token::GT, false)
106 REPLACE_COMPARE_IC_CALL(JSLessThanOrEqual, Token::LTE, false)
107 REPLACE_COMPARE_IC_CALL(JSGreaterThanOrEqual, Token::GTE, false)
108 #undef REPLACE_COMPARE_IC_CALL
109 
110 
111 #define REPLACE_RUNTIME_CALL(op, fun) \
112  void JSGenericLowering::Lower##op(Node* node) { \
113  ReplaceWithRuntimeCall(node, fun); \
114  }
115 REPLACE_RUNTIME_CALL(JSTypeOf, Runtime::kTypeof)
116 REPLACE_RUNTIME_CALL(JSCreate, Runtime::kAbort)
117 REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext)
118 REPLACE_RUNTIME_CALL(JSCreateCatchContext, Runtime::kPushCatchContext)
119 REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
120 REPLACE_RUNTIME_CALL(JSCreateBlockContext, Runtime::kPushBlockContext)
121 REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext)
122 REPLACE_RUNTIME_CALL(JSCreateGlobalContext, Runtime::kAbort)
123 #undef REPLACE_RUNTIME
124 
125 
126 #define REPLACE_UNIMPLEMENTED(op) \
127  void JSGenericLowering::Lower##op(Node* node) { UNIMPLEMENTED(); }
128 REPLACE_UNIMPLEMENTED(JSToName)
129 REPLACE_UNIMPLEMENTED(JSYield)
130 REPLACE_UNIMPLEMENTED(JSDebugger)
131 #undef REPLACE_UNIMPLEMENTED
132 
133 
134 static CallDescriptor::Flags FlagsForNode(Node* node) {
135  CallDescriptor::Flags result = CallDescriptor::kNoFlags;
136  if (OperatorProperties::HasFrameStateInput(node->op())) {
137  result |= CallDescriptor::kNeedsFrameState;
138  }
139  return result;
140 }
141 
142 
144  bool pure) {
145  Callable callable = CodeFactory::CompareIC(isolate(), token);
146  bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op());
147  CallDescriptor* desc_compare = linkage()->GetStubCallDescriptor(
148  callable.descriptor(), 0,
149  CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node));
150  NodeVector inputs(zone());
151  inputs.reserve(node->InputCount() + 1);
152  inputs.push_back(CodeConstant(callable.code()));
153  inputs.push_back(NodeProperties::GetValueInput(node, 0));
154  inputs.push_back(NodeProperties::GetValueInput(node, 1));
155  inputs.push_back(NodeProperties::GetContextInput(node));
156  if (pure) {
157  // A pure (strict) comparison doesn't have an effect, control or frame
158  // state. But for the graph, we need to add control and effect inputs.
159  DCHECK(!has_frame_state);
160  inputs.push_back(graph()->start());
161  inputs.push_back(graph()->start());
162  } else {
163  DCHECK(has_frame_state == FLAG_turbo_deoptimization);
164  if (FLAG_turbo_deoptimization) {
165  inputs.push_back(NodeProperties::GetFrameStateInput(node));
166  }
167  inputs.push_back(NodeProperties::GetEffectInput(node));
168  inputs.push_back(NodeProperties::GetControlInput(node));
169  }
170  Node* compare =
171  graph()->NewNode(common()->Call(desc_compare),
172  static_cast<int>(inputs.size()), &inputs.front());
173 
174  node->ReplaceInput(0, compare);
175  node->ReplaceInput(1, SmiConstant(token));
176 
177  if (has_frame_state) {
178  // Remove the frame state from inputs.
179  node->RemoveInput(NodeProperties::FirstFrameStateIndex(node));
180  }
181 
182  ReplaceWithRuntimeCall(node, Runtime::kBooleanize);
183 }
184 
185 
186 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
187  CallDescriptor::Flags flags) {
188  CallDescriptor* desc = linkage()->GetStubCallDescriptor(
189  callable.descriptor(), 0, flags | FlagsForNode(node));
190  Node* stub_code = CodeConstant(callable.code());
191  PatchInsertInput(node, 0, stub_code);
192  PatchOperator(node, common()->Call(desc));
193 }
194 
195 
198  int nargs) {
199  Callable callable =
200  CodeFactory::CallFunction(isolate(), nargs - 1, NO_CALL_FUNCTION_FLAGS);
201  CallDescriptor* desc =
202  linkage()->GetStubCallDescriptor(callable.descriptor(), nargs);
203  // TODO(mstarzinger): Accessing the builtins object this way prevents sharing
204  // of code across native contexts. Fix this by loading from given context.
205  Handle<JSFunction> function(
206  JSFunction::cast(info()->context()->builtins()->javascript_builtin(id)));
207  Node* stub_code = CodeConstant(callable.code());
208  Node* function_node = FunctionConstant(function);
209  PatchInsertInput(node, 0, stub_code);
210  PatchInsertInput(node, 1, function_node);
211  PatchOperator(node, common()->Call(desc));
212 }
213 
214 
217  int nargs_override) {
218  Operator::Properties properties = node->op()->properties();
220  int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
221  CallDescriptor* desc =
222  linkage()->GetRuntimeCallDescriptor(f, nargs, properties);
223  Node* ref = ExternalConstant(ExternalReference(f, isolate()));
224  Node* arity = Int32Constant(nargs);
225  if (!centrystub_constant_.is_set()) {
227  }
229  PatchInsertInput(node, nargs + 1, ref);
230  PatchInsertInput(node, nargs + 2, arity);
231  PatchOperator(node, common()->Call(desc));
232 }
233 
234 
235 void JSGenericLowering::LowerBranch(Node* node) {
236  if (!info()->is_typing_enabled()) {
237  // TODO(mstarzinger): If typing is enabled then simplified lowering will
238  // have inserted the correct ChangeBoolToBit, otherwise we need to perform
239  // poor-man's representation inference here and insert manual change.
240  Node* test = graph()->NewNode(machine()->WordEqual(), node->InputAt(0),
241  jsgraph()->TrueConstant());
242  node->ReplaceInput(0, test);
243  }
244 }
245 
246 
247 void JSGenericLowering::LowerJSUnaryNot(Node* node) {
248  Callable callable = CodeFactory::ToBoolean(
250  ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
251 }
252 
253 
254 void JSGenericLowering::LowerJSToBoolean(Node* node) {
255  Callable callable =
256  CodeFactory::ToBoolean(isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
257  ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
258 }
259 
260 
261 void JSGenericLowering::LowerJSToNumber(Node* node) {
262  Callable callable = CodeFactory::ToNumber(isolate());
263  ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags);
264 }
265 
266 
267 void JSGenericLowering::LowerJSToString(Node* node) {
268  ReplaceWithBuiltinCall(node, Builtins::TO_STRING, 1);
269 }
270 
271 
272 void JSGenericLowering::LowerJSToObject(Node* node) {
273  ReplaceWithBuiltinCall(node, Builtins::TO_OBJECT, 1);
274 }
275 
276 
277 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
278  Callable callable = CodeFactory::KeyedLoadIC(isolate());
279  ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
280 }
281 
282 
283 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
284  LoadNamedParameters p = OpParameter<LoadNamedParameters>(node);
285  Callable callable = CodeFactory::LoadIC(isolate(), p.contextual_mode);
286  PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name));
287  ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
288 }
289 
290 
291 void JSGenericLowering::LowerJSStoreProperty(Node* node) {
292  StrictMode strict_mode = OpParameter<StrictMode>(node);
293  Callable callable = CodeFactory::KeyedStoreIC(isolate(), strict_mode);
294  ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
295 }
296 
297 
298 void JSGenericLowering::LowerJSStoreNamed(Node* node) {
299  StoreNamedParameters params = OpParameter<StoreNamedParameters>(node);
300  Callable callable = CodeFactory::StoreIC(isolate(), params.strict_mode);
301  PatchInsertInput(node, 1, jsgraph()->HeapConstant(params.name));
302  ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
303 }
304 
305 
306 void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
307  StrictMode strict_mode = OpParameter<StrictMode>(node);
308  PatchInsertInput(node, 2, SmiConstant(strict_mode));
309  ReplaceWithBuiltinCall(node, Builtins::DELETE, 3);
310 }
311 
312 
313 void JSGenericLowering::LowerJSHasProperty(Node* node) {
315 }
316 
317 
318 void JSGenericLowering::LowerJSInstanceOf(Node* node) {
322  InstanceofStub stub(isolate(), flags);
323  CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
324  CallDescriptor* desc = linkage()->GetStubCallDescriptor(d, 0);
325  Node* stub_code = CodeConstant(stub.GetCode());
326  PatchInsertInput(node, 0, stub_code);
327  PatchOperator(node, common()->Call(desc));
328 }
329 
330 
331 void JSGenericLowering::LowerJSLoadContext(Node* node) {
332  ContextAccess access = OpParameter<ContextAccess>(node);
333  // TODO(mstarzinger): Use simplified operators instead of machine operators
334  // here so that load/store optimization can be applied afterwards.
335  for (int i = 0; i < access.depth(); ++i) {
336  node->ReplaceInput(
337  0, graph()->NewNode(
338  machine()->Load(kMachAnyTagged),
342  }
343  node->ReplaceInput(1, Int32Constant(Context::SlotOffset(access.index())));
344  PatchOperator(node, machine()->Load(kMachAnyTagged));
345 }
346 
347 
348 void JSGenericLowering::LowerJSStoreContext(Node* node) {
349  ContextAccess access = OpParameter<ContextAccess>(node);
350  // TODO(mstarzinger): Use simplified operators instead of machine operators
351  // here so that load/store optimization can be applied afterwards.
352  for (int i = 0; i < access.depth(); ++i) {
353  node->ReplaceInput(
354  0, graph()->NewNode(
355  machine()->Load(kMachAnyTagged),
359  }
360  node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
361  node->ReplaceInput(1, Int32Constant(Context::SlotOffset(access.index())));
362  PatchOperator(node, machine()->Store(StoreRepresentation(kMachAnyTagged,
364 }
365 
366 
367 void JSGenericLowering::LowerJSCallConstruct(Node* node) {
368  int arity = OpParameter<int>(node);
369  CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
370  CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
371  CallDescriptor* desc =
372  linkage()->GetStubCallDescriptor(d, arity, FlagsForNode(node));
373  Node* stub_code = CodeConstant(stub.GetCode());
374  Node* construct = NodeProperties::GetValueInput(node, 0);
375  PatchInsertInput(node, 0, stub_code);
376  PatchInsertInput(node, 1, Int32Constant(arity - 1));
377  PatchInsertInput(node, 2, construct);
378  PatchInsertInput(node, 3, jsgraph()->UndefinedConstant());
379  PatchOperator(node, common()->Call(desc));
380 }
381 
382 
383 void JSGenericLowering::LowerJSCallFunction(Node* node) {
384  CallParameters p = OpParameter<CallParameters>(node);
385  CallFunctionStub stub(isolate(), p.arity - 2, p.flags);
386  CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
387  CallDescriptor* desc =
388  linkage()->GetStubCallDescriptor(d, p.arity - 1, FlagsForNode(node));
389  Node* stub_code = CodeConstant(stub.GetCode());
390  PatchInsertInput(node, 0, stub_code);
391  PatchOperator(node, common()->Call(desc));
392 }
393 
394 
395 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
396  Runtime::FunctionId function = OpParameter<Runtime::FunctionId>(node);
397  int arity = OperatorProperties::GetValueInputCount(node->op());
398  ReplaceWithRuntimeCall(node, function, arity);
399 }
400 
401 } // namespace compiler
402 } // namespace internal
403 } // namespace v8
static int SlotOffset(int index)
Definition: contexts.h:552
static const Function * FunctionForId(FunctionId id)
Definition: runtime.cc:9312
void set(T *value)
Definition: utils.h:417
Node * NewNode(const Operator *op, int input_count, Node **inputs)
Definition: graph.cc:24
void ReplaceWithBuiltinCall(Node *node, Builtins::JavaScript id, int args)
MachineOperatorBuilder * machine() const
Node * FunctionConstant(Handle< JSFunction > function)
void ReplaceWithRuntimeCall(Node *node, Runtime::FunctionId f, int args=-1)
Node * ExternalConstant(ExternalReference ref)
void PatchOperator(Node *node, const Operator *new_op)
CommonOperatorBuilder * common() const
void ReplaceWithCompareIC(Node *node, Token::Value token, bool pure)
void PatchInsertInput(Node *node, int index, Node *input)
void ReplaceWithStubCall(Node *node, Callable c, CallDescriptor::Flags flags)
JSGenericLowering(CompilationInfo *info, JSGraph *graph)
Node * SmiConstant(int32_t immediate)
Definition: js-graph.h:81
Node * ExternalConstant(ExternalReference ref)
Definition: js-graph.cc:183
Node * Int32Constant(int32_t value)
Definition: js-graph.cc:150
Node * HeapConstant(Unique< Object > value)
Definition: js-graph.cc:96
CallDescriptor * GetStubCallDescriptor(CallInterfaceDescriptor descriptor, int stack_parameter_count=0, CallDescriptor::Flags flags=CallDescriptor::kNoFlags)
Definition: linkage.cc:103
CallDescriptor * GetRuntimeCallDescriptor(Runtime::FunctionId function, int parameter_count, Operator::Properties properties)
Definition: linkage.cc:95
static Node * GetContextInput(Node *node)
static Node * GetValueInput(Node *node, int index)
static Node * GetFrameStateInput(Node *node)
static Node * GetEffectInput(Node *node, int index=0)
static Node * GetControlInput(Node *node, int index=0)
static int GetValueInputCount(const Operator *op)
static bool HasFrameStateInput(const Operator *op)
base::Flags< Property, uint8_t > Properties
Definition: operator.h:48
static Reduction Changed(Node *node)
Definition: graph-reducer.h:48
enable harmony numeric enable harmony object literal extensions true
#define REPLACE_RUNTIME_CALL(op, fun)
#define DECLARE_CASE(x)
#define REPLACE_COMPARE_IC_CALL(op, token, pure)
#define REPLACE_UNIMPLEMENTED(op)
#define REPLACE_BINARY_OP_IC_CALL(op, token)
#define DCHECK(condition)
Definition: logging.h:205
int int32_t
Definition: unicode.cc:24
static CallDescriptor::Flags FlagsForNode(Node *node)
int ToNumber(Register reg)
@ NO_CALL_CONSTRUCTOR_FLAGS
Definition: globals.h:478
@ NO_CALL_FUNCTION_FLAGS
Definition: globals.h:469
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
#define JS_OP_LIST(V)
Definition: opcodes.h:125
#define IN