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"
7 #include "src/compiler/common-operator.h"
8 #include "src/compiler/js-generic-lowering.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/machine-operator.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/node-properties.h"
13 #include "src/compiler/operator-properties.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18 
AdjustFrameStatesForCall(Node * node)19 static CallDescriptor::Flags AdjustFrameStatesForCall(Node* node) {
20   int count = OperatorProperties::GetFrameStateInputCount(node->op());
21   if (count > 1) {
22     int index = NodeProperties::FirstFrameStateIndex(node) + 1;
23     do {
24       node->RemoveInput(index);
25     } while (--count > 1);
26   }
27   return count > 0 ? CallDescriptor::kNeedsFrameState
28                    : CallDescriptor::kNoFlags;
29 }
30 
31 
JSGenericLowering(bool is_typing_enabled,JSGraph * jsgraph)32 JSGenericLowering::JSGenericLowering(bool is_typing_enabled, JSGraph* jsgraph)
33     : is_typing_enabled_(is_typing_enabled), jsgraph_(jsgraph) {}
34 
35 
~JSGenericLowering()36 JSGenericLowering::~JSGenericLowering() {}
37 
38 
Reduce(Node * node)39 Reduction JSGenericLowering::Reduce(Node* node) {
40   switch (node->opcode()) {
41 #define DECLARE_CASE(x)  \
42     case IrOpcode::k##x: \
43       Lower##x(node);    \
44       break;
45     JS_OP_LIST(DECLARE_CASE)
46 #undef DECLARE_CASE
47     case IrOpcode::kBranch:
48       // TODO(mstarzinger): If typing is enabled then simplified lowering will
49       // have inserted the correct ChangeBoolToBit, otherwise we need to perform
50       // poor-man's representation inference here and insert manual change.
51       if (!is_typing_enabled_) {
52         Node* condition = node->InputAt(0);
53         Node* test = graph()->NewNode(machine()->WordEqual(), condition,
54                                       jsgraph()->TrueConstant());
55         node->ReplaceInput(0, test);
56       }
57       // Fall-through.
58     default:
59       // Nothing to see.
60       return NoChange();
61   }
62   return Changed(node);
63 }
64 
65 
66 #define REPLACE_BINARY_OP_IC_CALL(Op, token)                                  \
67   void JSGenericLowering::Lower##Op(Node* node) {                             \
68     BinaryOperationParameters const& p =                                      \
69         BinaryOperationParametersOf(node->op());                              \
70     CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);             \
71     ReplaceWithStubCall(node,                                                 \
72                         CodeFactory::BinaryOpIC(isolate(), token,             \
73                                                 strength(p.language_mode())), \
74                         CallDescriptor::kPatchableCallSiteWithNop | flags);   \
75   }
REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr,Token::BIT_OR)76 REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR)
77 REPLACE_BINARY_OP_IC_CALL(JSBitwiseXor, Token::BIT_XOR)
78 REPLACE_BINARY_OP_IC_CALL(JSBitwiseAnd, Token::BIT_AND)
79 REPLACE_BINARY_OP_IC_CALL(JSShiftLeft, Token::SHL)
80 REPLACE_BINARY_OP_IC_CALL(JSShiftRight, Token::SAR)
81 REPLACE_BINARY_OP_IC_CALL(JSShiftRightLogical, Token::SHR)
82 REPLACE_BINARY_OP_IC_CALL(JSAdd, Token::ADD)
83 REPLACE_BINARY_OP_IC_CALL(JSSubtract, Token::SUB)
84 REPLACE_BINARY_OP_IC_CALL(JSMultiply, Token::MUL)
85 REPLACE_BINARY_OP_IC_CALL(JSDivide, Token::DIV)
86 REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
87 #undef REPLACE_BINARY_OP_IC_CALL
88 
89 
90 // These ops are not language mode dependent; we arbitrarily pass Strength::WEAK
91 // here.
92 #define REPLACE_COMPARE_IC_CALL(op, token)             \
93   void JSGenericLowering::Lower##op(Node* node) {      \
94     ReplaceWithCompareIC(node, token, Strength::WEAK); \
95   }
96 REPLACE_COMPARE_IC_CALL(JSEqual, Token::EQ)
97 REPLACE_COMPARE_IC_CALL(JSNotEqual, Token::NE)
98 REPLACE_COMPARE_IC_CALL(JSStrictEqual, Token::EQ_STRICT)
99 REPLACE_COMPARE_IC_CALL(JSStrictNotEqual, Token::NE_STRICT)
100 #undef REPLACE_COMPARE_IC_CALL
101 
102 
103 #define REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(op, token)        \
104   void JSGenericLowering::Lower##op(Node* node) {                    \
105     ReplaceWithCompareIC(node, token,                                \
106                          strength(OpParameter<LanguageMode>(node))); \
107   }
108 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSLessThan, Token::LT)
109 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThan, Token::GT)
110 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSLessThanOrEqual, Token::LTE)
111 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThanOrEqual, Token::GTE)
112 #undef REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE
113 
114 
115 #define REPLACE_RUNTIME_CALL(op, fun)             \
116   void JSGenericLowering::Lower##op(Node* node) { \
117     ReplaceWithRuntimeCall(node, fun);            \
118   }
119 REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext)
120 REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
121 REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext)
122 REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver)
123 #undef REPLACE_RUNTIME
124 
125 
126 static CallDescriptor::Flags FlagsForNode(Node* node) {
127   CallDescriptor::Flags result = CallDescriptor::kNoFlags;
128   if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
129     result |= CallDescriptor::kNeedsFrameState;
130   }
131   return result;
132 }
133 
134 
ReplaceWithCompareIC(Node * node,Token::Value token,Strength str)135 void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token,
136                                              Strength str) {
137   Callable callable = CodeFactory::CompareIC(isolate(), token, str);
138 
139   // Create a new call node asking a CompareIC for help.
140   NodeVector inputs(zone());
141   inputs.reserve(node->InputCount() + 1);
142   inputs.push_back(jsgraph()->HeapConstant(callable.code()));
143   inputs.push_back(NodeProperties::GetValueInput(node, 0));
144   inputs.push_back(NodeProperties::GetValueInput(node, 1));
145   inputs.push_back(NodeProperties::GetContextInput(node));
146   // Some comparisons (StrictEqual) don't have an effect, control or frame
147   // state inputs, so handle those cases here.
148   if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
149     inputs.push_back(NodeProperties::GetFrameStateInput(node, 0));
150   }
151   Node* effect = (node->op()->EffectInputCount() > 0)
152                      ? NodeProperties::GetEffectInput(node)
153                      : graph()->start();
154   inputs.push_back(effect);
155   Node* control = (node->op()->ControlInputCount() > 0)
156                       ? NodeProperties::GetControlInput(node)
157                       : graph()->start();
158   inputs.push_back(control);
159   CallDescriptor* desc_compare = Linkage::GetStubCallDescriptor(
160       isolate(), zone(), callable.descriptor(), 0,
161       CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node),
162       Operator::kNoProperties, MachineType::IntPtr());
163   Node* compare =
164       graph()->NewNode(common()->Call(desc_compare),
165                        static_cast<int>(inputs.size()), &inputs.front());
166 
167   // Decide how the return value from the above CompareIC can be converted into
168   // a JavaScript boolean oddball depending on the given token.
169   Node* false_value = jsgraph()->FalseConstant();
170   Node* true_value = jsgraph()->TrueConstant();
171   const Operator* op = nullptr;
172   switch (token) {
173     case Token::EQ:  // a == 0
174     case Token::EQ_STRICT:
175       op = machine()->WordEqual();
176       break;
177     case Token::NE:  // a != 0 becomes !(a == 0)
178     case Token::NE_STRICT:
179       op = machine()->WordEqual();
180       std::swap(true_value, false_value);
181       break;
182     case Token::LT:  // a < 0
183       op = machine()->IntLessThan();
184       break;
185     case Token::GT:  // a > 0 becomes !(a <= 0)
186       op = machine()->IntLessThanOrEqual();
187       std::swap(true_value, false_value);
188       break;
189     case Token::LTE:  // a <= 0
190       op = machine()->IntLessThanOrEqual();
191       break;
192     case Token::GTE:  // a >= 0 becomes !(a < 0)
193       op = machine()->IntLessThan();
194       std::swap(true_value, false_value);
195       break;
196     default:
197       UNREACHABLE();
198   }
199   Node* booleanize = graph()->NewNode(op, compare, jsgraph()->ZeroConstant());
200 
201   // Finally patch the original node to select a boolean.
202   NodeProperties::ReplaceUses(node, node, compare, compare, compare);
203   node->TrimInputCount(3);
204   node->ReplaceInput(0, booleanize);
205   node->ReplaceInput(1, true_value);
206   node->ReplaceInput(2, false_value);
207   NodeProperties::ChangeOp(node,
208                            common()->Select(MachineRepresentation::kTagged));
209 }
210 
211 
ReplaceWithStubCall(Node * node,Callable callable,CallDescriptor::Flags flags)212 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
213                                             CallDescriptor::Flags flags) {
214   Operator::Properties properties = node->op()->properties();
215   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
216       isolate(), zone(), callable.descriptor(), 0, flags, properties);
217   Node* stub_code = jsgraph()->HeapConstant(callable.code());
218   node->InsertInput(zone(), 0, stub_code);
219   NodeProperties::ChangeOp(node, common()->Call(desc));
220 }
221 
222 
ReplaceWithRuntimeCall(Node * node,Runtime::FunctionId f,int nargs_override)223 void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
224                                                Runtime::FunctionId f,
225                                                int nargs_override) {
226   Operator::Properties properties = node->op()->properties();
227   const Runtime::Function* fun = Runtime::FunctionForId(f);
228   int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
229   CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
230       zone(), f, nargs, properties, CallDescriptor::kNeedsFrameState);
231   Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate()));
232   Node* arity = jsgraph()->Int32Constant(nargs);
233   node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
234   node->InsertInput(zone(), nargs + 1, ref);
235   node->InsertInput(zone(), nargs + 2, arity);
236   NodeProperties::ChangeOp(node, common()->Call(desc));
237 }
238 
239 
LowerJSTypeOf(Node * node)240 void JSGenericLowering::LowerJSTypeOf(Node* node) {
241   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
242   Callable callable = CodeFactory::Typeof(isolate());
243   ReplaceWithStubCall(node, callable, flags);
244 }
245 
246 
LowerJSToBoolean(Node * node)247 void JSGenericLowering::LowerJSToBoolean(Node* node) {
248   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
249   Callable callable = CodeFactory::ToBoolean(isolate());
250   ReplaceWithStubCall(node, callable,
251                       CallDescriptor::kPatchableCallSite | flags);
252 }
253 
254 
LowerJSToNumber(Node * node)255 void JSGenericLowering::LowerJSToNumber(Node* node) {
256   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
257   Callable callable = CodeFactory::ToNumber(isolate());
258   ReplaceWithStubCall(node, callable, flags);
259 }
260 
261 
LowerJSToString(Node * node)262 void JSGenericLowering::LowerJSToString(Node* node) {
263   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
264   Callable callable = CodeFactory::ToString(isolate());
265   ReplaceWithStubCall(node, callable, flags);
266 }
267 
268 
LowerJSToName(Node * node)269 void JSGenericLowering::LowerJSToName(Node* node) {
270   ReplaceWithRuntimeCall(node, Runtime::kToName);
271 }
272 
273 
LowerJSToObject(Node * node)274 void JSGenericLowering::LowerJSToObject(Node* node) {
275   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
276   Callable callable = CodeFactory::ToObject(isolate());
277   ReplaceWithStubCall(node, callable, flags);
278 }
279 
280 
LowerJSLoadProperty(Node * node)281 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
282   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
283   const PropertyAccess& p = PropertyAccessOf(node->op());
284   Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(
285       isolate(), p.language_mode(), UNINITIALIZED);
286   node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
287   ReplaceWithStubCall(node, callable, flags);
288 }
289 
290 
LowerJSLoadNamed(Node * node)291 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
292   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
293   NamedAccess const& p = NamedAccessOf(node->op());
294   Callable callable = CodeFactory::LoadICInOptimizedCode(
295       isolate(), NOT_INSIDE_TYPEOF, p.language_mode(), UNINITIALIZED);
296   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
297   node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
298   ReplaceWithStubCall(node, callable, flags);
299 }
300 
301 
LowerJSLoadGlobal(Node * node)302 void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
303   Node* context = NodeProperties::GetContextInput(node);
304   Node* effect = NodeProperties::GetEffectInput(node);
305   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
306   const LoadGlobalParameters& p = LoadGlobalParametersOf(node->op());
307   Callable callable = CodeFactory::LoadICInOptimizedCode(
308       isolate(), p.typeof_mode(), SLOPPY, UNINITIALIZED);
309   // Load global object from the context.
310   Node* native_context =
311       graph()->NewNode(machine()->Load(MachineType::AnyTagged()), context,
312                        jsgraph()->IntPtrConstant(
313                            Context::SlotOffset(Context::NATIVE_CONTEXT_INDEX)),
314                        effect, graph()->start());
315   Node* global = graph()->NewNode(
316       machine()->Load(MachineType::AnyTagged()), native_context,
317       jsgraph()->IntPtrConstant(Context::SlotOffset(Context::EXTENSION_INDEX)),
318       effect, graph()->start());
319   node->InsertInput(zone(), 0, global);
320   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
321   node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
322   ReplaceWithStubCall(node, callable, flags);
323 }
324 
325 
LowerJSStoreProperty(Node * node)326 void JSGenericLowering::LowerJSStoreProperty(Node* node) {
327   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
328   PropertyAccess const& p = PropertyAccessOf(node->op());
329   LanguageMode language_mode = p.language_mode();
330   Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
331       isolate(), language_mode, UNINITIALIZED);
332   DCHECK(p.feedback().index() != -1);
333   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
334   ReplaceWithStubCall(node, callable,
335                       CallDescriptor::kPatchableCallSite | flags);
336 }
337 
338 
LowerJSStoreNamed(Node * node)339 void JSGenericLowering::LowerJSStoreNamed(Node* node) {
340   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
341   NamedAccess const& p = NamedAccessOf(node->op());
342   Callable callable = CodeFactory::StoreICInOptimizedCode(
343       isolate(), p.language_mode(), UNINITIALIZED);
344   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
345   DCHECK(p.feedback().index() != -1);
346   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
347   ReplaceWithStubCall(node, callable,
348                       CallDescriptor::kPatchableCallSite | flags);
349 }
350 
351 
LowerJSStoreGlobal(Node * node)352 void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
353   Node* context = NodeProperties::GetContextInput(node);
354   Node* effect = NodeProperties::GetEffectInput(node);
355   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
356   const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
357   Callable callable = CodeFactory::StoreICInOptimizedCode(
358       isolate(), p.language_mode(), UNINITIALIZED);
359   // Load global object from the context.
360   Node* native_context =
361       graph()->NewNode(machine()->Load(MachineType::AnyTagged()), context,
362                        jsgraph()->IntPtrConstant(
363                            Context::SlotOffset(Context::NATIVE_CONTEXT_INDEX)),
364                        effect, graph()->start());
365   Node* global = graph()->NewNode(
366       machine()->Load(MachineType::AnyTagged()), native_context,
367       jsgraph()->IntPtrConstant(Context::SlotOffset(Context::EXTENSION_INDEX)),
368       effect, graph()->start());
369   node->InsertInput(zone(), 0, global);
370   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
371   DCHECK(p.feedback().index() != -1);
372   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
373   ReplaceWithStubCall(node, callable,
374                       CallDescriptor::kPatchableCallSite | flags);
375 }
376 
377 
LowerJSDeleteProperty(Node * node)378 void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
379   LanguageMode language_mode = OpParameter<LanguageMode>(node);
380   ReplaceWithRuntimeCall(node, is_strict(language_mode)
381                                    ? Runtime::kDeleteProperty_Strict
382                                    : Runtime::kDeleteProperty_Sloppy);
383 }
384 
385 
LowerJSHasProperty(Node * node)386 void JSGenericLowering::LowerJSHasProperty(Node* node) {
387   ReplaceWithRuntimeCall(node, Runtime::kHasProperty);
388 }
389 
390 
LowerJSInstanceOf(Node * node)391 void JSGenericLowering::LowerJSInstanceOf(Node* node) {
392   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
393   Callable callable = CodeFactory::InstanceOf(isolate());
394   ReplaceWithStubCall(node, callable, flags);
395 }
396 
397 
LowerJSLoadContext(Node * node)398 void JSGenericLowering::LowerJSLoadContext(Node* node) {
399   const ContextAccess& access = ContextAccessOf(node->op());
400   for (size_t i = 0; i < access.depth(); ++i) {
401     node->ReplaceInput(
402         0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()),
403                             NodeProperties::GetValueInput(node, 0),
404                             jsgraph()->Int32Constant(
405                                 Context::SlotOffset(Context::PREVIOUS_INDEX)),
406                             NodeProperties::GetEffectInput(node),
407                             graph()->start()));
408   }
409   node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
410                             static_cast<int>(access.index()))));
411   node->AppendInput(zone(), graph()->start());
412   NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged()));
413 }
414 
415 
LowerJSStoreContext(Node * node)416 void JSGenericLowering::LowerJSStoreContext(Node* node) {
417   const ContextAccess& access = ContextAccessOf(node->op());
418   for (size_t i = 0; i < access.depth(); ++i) {
419     node->ReplaceInput(
420         0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()),
421                             NodeProperties::GetValueInput(node, 0),
422                             jsgraph()->Int32Constant(
423                                 Context::SlotOffset(Context::PREVIOUS_INDEX)),
424                             NodeProperties::GetEffectInput(node),
425                             graph()->start()));
426   }
427   node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
428   node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
429                             static_cast<int>(access.index()))));
430   NodeProperties::ChangeOp(
431       node, machine()->Store(StoreRepresentation(MachineRepresentation::kTagged,
432                                                  kFullWriteBarrier)));
433 }
434 
435 
LowerJSLoadDynamic(Node * node)436 void JSGenericLowering::LowerJSLoadDynamic(Node* node) {
437   const DynamicAccess& access = DynamicAccessOf(node->op());
438   Runtime::FunctionId function_id =
439       (access.typeof_mode() == NOT_INSIDE_TYPEOF)
440           ? Runtime::kLoadLookupSlot
441           : Runtime::kLoadLookupSlotNoReferenceError;
442   Node* projection = graph()->NewNode(common()->Projection(0), node);
443   NodeProperties::ReplaceUses(node, projection, node, node, node);
444   node->RemoveInput(NodeProperties::FirstValueIndex(node));
445   node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
446   ReplaceWithRuntimeCall(node, function_id);
447   projection->ReplaceInput(0, node);
448 }
449 
450 
LowerJSCreate(Node * node)451 void JSGenericLowering::LowerJSCreate(Node* node) {
452   ReplaceWithRuntimeCall(node, Runtime::kNewObject);
453 }
454 
455 
LowerJSCreateArguments(Node * node)456 void JSGenericLowering::LowerJSCreateArguments(Node* node) {
457   const CreateArgumentsParameters& p = CreateArgumentsParametersOf(node->op());
458   switch (p.type()) {
459     case CreateArgumentsParameters::kMappedArguments:
460       ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments_Generic);
461       break;
462     case CreateArgumentsParameters::kUnmappedArguments:
463       ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments_Generic);
464       break;
465     case CreateArgumentsParameters::kRestArray:
466       node->InsertInput(zone(), 1, jsgraph()->Constant(p.start_index()));
467       ReplaceWithRuntimeCall(node, Runtime::kNewRestArguments_Generic);
468       break;
469   }
470 }
471 
472 
LowerJSCreateArray(Node * node)473 void JSGenericLowering::LowerJSCreateArray(Node* node) {
474   CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
475   int const arity = static_cast<int>(p.arity());
476   Node* new_target = node->InputAt(1);
477   // TODO(turbofan): We embed the AllocationSite from the Operator at this
478   // point, which we should not do once we want to both consume the feedback
479   // but at the same time shared the optimized code across native contexts,
480   // as the AllocationSite is associated with a single native context (it's
481   // stored in the type feedback vector after all). Once we go for cross
482   // context code generation, we should somehow find a way to get to the
483   // allocation site for the actual native context at runtime.
484   Node* type_info = p.site().is_null() ? jsgraph()->UndefinedConstant()
485                                        : jsgraph()->HeapConstant(p.site());
486   node->RemoveInput(1);
487   node->InsertInput(zone(), 1 + arity, new_target);
488   node->InsertInput(zone(), 2 + arity, type_info);
489   ReplaceWithRuntimeCall(node, Runtime::kNewArray, arity + 3);
490 }
491 
492 
LowerJSCreateClosure(Node * node)493 void JSGenericLowering::LowerJSCreateClosure(Node* node) {
494   CreateClosureParameters p = CreateClosureParametersOf(node->op());
495   node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.shared_info()));
496   ReplaceWithRuntimeCall(node, (p.pretenure() == TENURED)
497                                    ? Runtime::kNewClosure_Tenured
498                                    : Runtime::kNewClosure);
499 }
500 
501 
LowerJSCreateIterResultObject(Node * node)502 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
503   ReplaceWithRuntimeCall(node, Runtime::kCreateIterResultObject);
504 }
505 
506 
LowerJSCreateLiteralArray(Node * node)507 void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
508   CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
509   node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index()));
510   node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
511   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
512   ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
513 }
514 
515 
LowerJSCreateLiteralObject(Node * node)516 void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
517   CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
518   node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index()));
519   node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
520   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
521   ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
522 }
523 
524 
LowerJSCreateLiteralRegExp(Node * node)525 void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
526   CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
527   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
528   Callable callable = CodeFactory::FastCloneRegExp(isolate());
529   Node* literal_index = jsgraph()->SmiConstant(p.index());
530   Node* literal_flags = jsgraph()->SmiConstant(p.flags());
531   Node* pattern = jsgraph()->HeapConstant(p.constant());
532   node->InsertInput(graph()->zone(), 1, literal_index);
533   node->InsertInput(graph()->zone(), 2, pattern);
534   node->InsertInput(graph()->zone(), 3, literal_flags);
535   ReplaceWithStubCall(node, callable, flags);
536 }
537 
538 
LowerJSCreateCatchContext(Node * node)539 void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
540   Handle<String> name = OpParameter<Handle<String>>(node);
541   node->InsertInput(zone(), 0, jsgraph()->HeapConstant(name));
542   ReplaceWithRuntimeCall(node, Runtime::kPushCatchContext);
543 }
544 
545 
LowerJSCreateBlockContext(Node * node)546 void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
547   Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
548   node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
549   ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
550 }
551 
552 
LowerJSCreateScriptContext(Node * node)553 void JSGenericLowering::LowerJSCreateScriptContext(Node* node) {
554   Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
555   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(scope_info));
556   ReplaceWithRuntimeCall(node, Runtime::kNewScriptContext);
557 }
558 
559 
LowerJSCallConstruct(Node * node)560 void JSGenericLowering::LowerJSCallConstruct(Node* node) {
561   CallConstructParameters const& p = CallConstructParametersOf(node->op());
562   int const arg_count = static_cast<int>(p.arity() - 2);
563   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
564   Callable callable = CodeFactory::Construct(isolate());
565   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
566       isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
567   Node* stub_code = jsgraph()->HeapConstant(callable.code());
568   Node* stub_arity = jsgraph()->Int32Constant(arg_count);
569   Node* new_target = node->InputAt(arg_count + 1);
570   Node* receiver = jsgraph()->UndefinedConstant();
571   node->RemoveInput(arg_count + 1);  // Drop new target.
572   node->InsertInput(zone(), 0, stub_code);
573   node->InsertInput(zone(), 2, new_target);
574   node->InsertInput(zone(), 3, stub_arity);
575   node->InsertInput(zone(), 4, receiver);
576   NodeProperties::ChangeOp(node, common()->Call(desc));
577 }
578 
579 
LowerJSCallFunction(Node * node)580 void JSGenericLowering::LowerJSCallFunction(Node* node) {
581   CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
582   int const arg_count = static_cast<int>(p.arity() - 2);
583   ConvertReceiverMode const mode = p.convert_mode();
584   Callable callable = CodeFactory::Call(isolate(), mode);
585   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
586   if (p.tail_call_mode() == TailCallMode::kAllow) {
587     flags |= CallDescriptor::kSupportsTailCalls;
588   }
589   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
590       isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
591   Node* stub_code = jsgraph()->HeapConstant(callable.code());
592   Node* stub_arity = jsgraph()->Int32Constant(arg_count);
593   node->InsertInput(zone(), 0, stub_code);
594   node->InsertInput(zone(), 2, stub_arity);
595   NodeProperties::ChangeOp(node, common()->Call(desc));
596 }
597 
598 
LowerJSCallRuntime(Node * node)599 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
600   const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
601   AdjustFrameStatesForCall(node);
602   ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
603 }
604 
605 
LowerJSForInDone(Node * node)606 void JSGenericLowering::LowerJSForInDone(Node* node) {
607   ReplaceWithRuntimeCall(node, Runtime::kForInDone);
608 }
609 
610 
LowerJSForInNext(Node * node)611 void JSGenericLowering::LowerJSForInNext(Node* node) {
612   ReplaceWithRuntimeCall(node, Runtime::kForInNext);
613 }
614 
615 
LowerJSForInPrepare(Node * node)616 void JSGenericLowering::LowerJSForInPrepare(Node* node) {
617   Node* object = NodeProperties::GetValueInput(node, 0);
618   Node* context = NodeProperties::GetContextInput(node);
619   Node* effect = NodeProperties::GetEffectInput(node);
620   Node* control = NodeProperties::GetControlInput(node);
621   Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
622 
623   // Get the set of properties to enumerate.
624   Runtime::Function const* function =
625       Runtime::FunctionForId(Runtime::kGetPropertyNamesFast);
626   CallDescriptor const* descriptor = Linkage::GetRuntimeCallDescriptor(
627       zone(), function->function_id, 1, Operator::kNoProperties,
628       CallDescriptor::kNeedsFrameState);
629   Node* cache_type = effect = graph()->NewNode(
630       common()->Call(descriptor),
631       jsgraph()->CEntryStubConstant(function->result_size), object,
632       jsgraph()->ExternalConstant(function->function_id),
633       jsgraph()->Int32Constant(1), context, frame_state, effect, control);
634   control = graph()->NewNode(common()->IfSuccess(), cache_type);
635 
636   Node* object_map = effect = graph()->NewNode(
637       machine()->Load(MachineType::AnyTagged()), object,
638       jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag),
639       effect, control);
640   Node* cache_type_map = effect = graph()->NewNode(
641       machine()->Load(MachineType::AnyTagged()), cache_type,
642       jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag),
643       effect, control);
644   Node* meta_map = jsgraph()->HeapConstant(isolate()->factory()->meta_map());
645 
646   // If we got a map from the GetPropertyNamesFast runtime call, we can do a
647   // fast modification check. Otherwise, we got a fixed array, and we have to
648   // perform a slow check on every iteration.
649   Node* check0 =
650       graph()->NewNode(machine()->WordEqual(), cache_type_map, meta_map);
651   Node* branch0 =
652       graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
653 
654   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
655   Node* cache_array_true0;
656   Node* cache_length_true0;
657   Node* cache_type_true0;
658   Node* etrue0;
659   {
660     // Enum cache case.
661     Node* cache_type_enum_length = etrue0 = graph()->NewNode(
662         machine()->Load(MachineType::Uint32()), cache_type,
663         jsgraph()->IntPtrConstant(Map::kBitField3Offset - kHeapObjectTag),
664         effect, if_true0);
665     cache_type_enum_length =
666         graph()->NewNode(machine()->Word32And(), cache_type_enum_length,
667                          jsgraph()->Uint32Constant(Map::EnumLengthBits::kMask));
668 
669     Node* check1 =
670         graph()->NewNode(machine()->Word32Equal(), cache_type_enum_length,
671                          jsgraph()->Int32Constant(0));
672     Node* branch1 =
673         graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0);
674 
675     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
676     Node* cache_array_true1;
677     Node* etrue1;
678     {
679       // No properties to enumerate.
680       cache_array_true1 =
681           jsgraph()->HeapConstant(isolate()->factory()->empty_fixed_array());
682       etrue1 = etrue0;
683     }
684 
685     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
686     Node* cache_array_false1;
687     Node* efalse1;
688     {
689       // Load the enumeration cache from the instance descriptors of {object}.
690       Node* object_map_descriptors = efalse1 = graph()->NewNode(
691           machine()->Load(MachineType::AnyTagged()), object_map,
692           jsgraph()->IntPtrConstant(Map::kDescriptorsOffset - kHeapObjectTag),
693           etrue0, if_false1);
694       Node* object_map_enum_cache = efalse1 = graph()->NewNode(
695           machine()->Load(MachineType::AnyTagged()), object_map_descriptors,
696           jsgraph()->IntPtrConstant(DescriptorArray::kEnumCacheOffset -
697                                     kHeapObjectTag),
698           efalse1, if_false1);
699       cache_array_false1 = efalse1 = graph()->NewNode(
700           machine()->Load(MachineType::AnyTagged()), object_map_enum_cache,
701           jsgraph()->IntPtrConstant(
702               DescriptorArray::kEnumCacheBridgeCacheOffset - kHeapObjectTag),
703           efalse1, if_false1);
704     }
705 
706     if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
707     etrue0 =
708         graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0);
709     cache_array_true0 =
710         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
711                          cache_array_true1, cache_array_false1, if_true0);
712 
713     cache_length_true0 = graph()->NewNode(
714         machine()->WordShl(),
715         machine()->Is64()
716             ? graph()->NewNode(machine()->ChangeUint32ToUint64(),
717                                cache_type_enum_length)
718             : cache_type_enum_length,
719         jsgraph()->Int32Constant(kSmiShiftSize + kSmiTagSize));
720     cache_type_true0 = cache_type;
721   }
722 
723   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
724   Node* cache_array_false0;
725   Node* cache_length_false0;
726   Node* cache_type_false0;
727   Node* efalse0;
728   {
729     // FixedArray case.
730     cache_type_false0 = jsgraph()->OneConstant();  // Smi means slow check
731     cache_array_false0 = cache_type;
732     cache_length_false0 = efalse0 = graph()->NewNode(
733         machine()->Load(MachineType::AnyTagged()), cache_array_false0,
734         jsgraph()->IntPtrConstant(FixedArray::kLengthOffset - kHeapObjectTag),
735         effect, if_false0);
736   }
737 
738   control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
739   effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
740   Node* cache_array =
741       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
742                        cache_array_true0, cache_array_false0, control);
743   Node* cache_length =
744       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
745                        cache_length_true0, cache_length_false0, control);
746   cache_type =
747       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
748                        cache_type_true0, cache_type_false0, control);
749 
750   for (auto edge : node->use_edges()) {
751     if (NodeProperties::IsEffectEdge(edge)) {
752       edge.UpdateTo(effect);
753     } else if (NodeProperties::IsControlEdge(edge)) {
754       Node* const use = edge.from();
755       if (use->opcode() == IrOpcode::kIfSuccess) {
756         use->ReplaceUses(control);
757         use->Kill();
758       } else if (use->opcode() == IrOpcode::kIfException) {
759         edge.UpdateTo(cache_type_true0);
760       } else {
761         UNREACHABLE();
762       }
763     } else {
764       Node* const use = edge.from();
765       DCHECK(NodeProperties::IsValueEdge(edge));
766       DCHECK_EQ(IrOpcode::kProjection, use->opcode());
767       switch (ProjectionIndexOf(use->op())) {
768         case 0:
769           use->ReplaceUses(cache_type);
770           break;
771         case 1:
772           use->ReplaceUses(cache_array);
773           break;
774         case 2:
775           use->ReplaceUses(cache_length);
776           break;
777         default:
778           UNREACHABLE();
779           break;
780       }
781       use->Kill();
782     }
783   }
784 }
785 
786 
LowerJSForInStep(Node * node)787 void JSGenericLowering::LowerJSForInStep(Node* node) {
788   ReplaceWithRuntimeCall(node, Runtime::kForInStep);
789 }
790 
791 
LowerJSLoadMessage(Node * node)792 void JSGenericLowering::LowerJSLoadMessage(Node* node) {
793   ExternalReference message_address =
794       ExternalReference::address_of_pending_message_obj(isolate());
795   node->RemoveInput(NodeProperties::FirstContextIndex(node));
796   node->InsertInput(zone(), 0, jsgraph()->ExternalConstant(message_address));
797   node->InsertInput(zone(), 1, jsgraph()->IntPtrConstant(0));
798   NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged()));
799 }
800 
801 
LowerJSStoreMessage(Node * node)802 void JSGenericLowering::LowerJSStoreMessage(Node* node) {
803   ExternalReference message_address =
804       ExternalReference::address_of_pending_message_obj(isolate());
805   node->RemoveInput(NodeProperties::FirstContextIndex(node));
806   node->InsertInput(zone(), 0, jsgraph()->ExternalConstant(message_address));
807   node->InsertInput(zone(), 1, jsgraph()->IntPtrConstant(0));
808   StoreRepresentation representation(MachineRepresentation::kTagged,
809                                      kNoWriteBarrier);
810   NodeProperties::ChangeOp(node, machine()->Store(representation));
811 }
812 
813 
LowerJSYield(Node * node)814 void JSGenericLowering::LowerJSYield(Node* node) { UNIMPLEMENTED(); }
815 
816 
LowerJSStackCheck(Node * node)817 void JSGenericLowering::LowerJSStackCheck(Node* node) {
818   Node* effect = NodeProperties::GetEffectInput(node);
819   Node* control = NodeProperties::GetControlInput(node);
820 
821   Node* limit = graph()->NewNode(
822       machine()->Load(MachineType::Pointer()),
823       jsgraph()->ExternalConstant(
824           ExternalReference::address_of_stack_limit(isolate())),
825       jsgraph()->IntPtrConstant(0), effect, control);
826   Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
827 
828   Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
829   Node* branch =
830       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
831 
832   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
833   Node* etrue = effect;
834 
835   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
836   NodeProperties::ReplaceControlInput(node, if_false);
837   Node* efalse = node;
838 
839   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
840   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
841 
842   // Wire the new diamond into the graph, {node} can still throw.
843   NodeProperties::ReplaceUses(node, node, ephi, node, node);
844   NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
845 
846   // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
847   // the node and places it inside the diamond. Come up with a helper method!
848   for (Node* use : node->uses()) {
849     if (use->opcode() == IrOpcode::kIfSuccess) {
850       use->ReplaceUses(merge);
851       merge->ReplaceInput(1, use);
852     }
853   }
854 
855   // Turn the stack check into a runtime call.
856   ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
857 }
858 
859 
zone() const860 Zone* JSGenericLowering::zone() const { return graph()->zone(); }
861 
862 
isolate() const863 Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
864 
865 
graph() const866 Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
867 
868 
common() const869 CommonOperatorBuilder* JSGenericLowering::common() const {
870   return jsgraph()->common();
871 }
872 
873 
machine() const874 MachineOperatorBuilder* JSGenericLowering::machine() const {
875   return jsgraph()->machine();
876 }
877 
878 }  // namespace compiler
879 }  // namespace internal
880 }  // namespace v8
881