Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 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" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 8 | #include "src/compiler/js-generic-lowering.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 9 | #include "src/compiler/js-graph.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 10 | #include "src/compiler/machine-operator.h" |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 11 | #include "src/compiler/node-matchers.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 12 | #include "src/compiler/node-properties.h" |
| 13 | #include "src/compiler/operator-properties.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 14 | |
| 15 | namespace v8 { |
| 16 | namespace internal { |
| 17 | namespace compiler { |
| 18 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 29 | } |
| 30 | |
| 31 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 32 | JSGenericLowering::JSGenericLowering(bool is_typing_enabled, JSGraph* jsgraph) |
| 33 | : is_typing_enabled_(is_typing_enabled), jsgraph_(jsgraph) {} |
| 34 | |
| 35 | |
| 36 | JSGenericLowering::~JSGenericLowering() {} |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 37 | |
| 38 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 39 | Reduction JSGenericLowering::Reduce(Node* node) { |
| 40 | switch (node->opcode()) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 41 | #define DECLARE_CASE(x) \ |
| 42 | case IrOpcode::k##x: \ |
| 43 | Lower##x(node); \ |
| 44 | break; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 45 | JS_OP_LIST(DECLARE_CASE) |
| 46 | #undef DECLARE_CASE |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 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. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 51 | if (!is_typing_enabled_) { |
| 52 | Node* condition = node->InputAt(0); |
| 53 | Node* test = graph()->NewNode(machine()->WordEqual(), condition, |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 54 | jsgraph()->TrueConstant()); |
| 55 | node->ReplaceInput(0, test); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 56 | } |
| 57 | // Fall-through. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 58 | default: |
| 59 | // Nothing to see. |
| 60 | return NoChange(); |
| 61 | } |
| 62 | return Changed(node); |
| 63 | } |
| 64 | |
| 65 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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); \ |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 75 | } |
| 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 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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); \ |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 95 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 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) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 100 | #undef REPLACE_COMPARE_IC_CALL |
| 101 | |
| 102 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 115 | #define REPLACE_RUNTIME_CALL(op, fun) \ |
| 116 | void JSGenericLowering::Lower##op(Node* node) { \ |
| 117 | ReplaceWithRuntimeCall(node, fun); \ |
| 118 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 119 | REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 120 | REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 121 | REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext) |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 122 | REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 123 | #undef REPLACE_RUNTIME |
| 124 | |
| 125 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 126 | static CallDescriptor::Flags FlagsForNode(Node* node) { |
| 127 | CallDescriptor::Flags result = CallDescriptor::kNoFlags; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 128 | if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 129 | result |= CallDescriptor::kNeedsFrameState; |
| 130 | } |
| 131 | return result; |
| 132 | } |
| 133 | |
| 134 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 140 | NodeVector inputs(zone()); |
| 141 | inputs.reserve(node->InputCount() + 1); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 142 | inputs.push_back(jsgraph()->HeapConstant(callable.code())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 143 | inputs.push_back(NodeProperties::GetValueInput(node, 0)); |
| 144 | inputs.push_back(NodeProperties::GetValueInput(node, 1)); |
| 145 | inputs.push_back(NodeProperties::GetContextInput(node)); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 150 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 163 | Node* compare = |
| 164 | graph()->NewNode(common()->Call(desc_compare), |
| 165 | static_cast<int>(inputs.size()), &inputs.front()); |
| 166 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 198 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 199 | Node* booleanize = graph()->NewNode(op, compare, jsgraph()->ZeroConstant()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 200 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 209 | } |
| 210 | |
| 211 | |
| 212 | void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable, |
| 213 | CallDescriptor::Flags flags) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 214 | Operator::Properties properties = node->op()->properties(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 215 | CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
| 216 | isolate(), zone(), callable.descriptor(), 0, flags, properties); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 217 | Node* stub_code = jsgraph()->HeapConstant(callable.code()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 218 | node->InsertInput(zone(), 0, stub_code); |
| 219 | NodeProperties::ChangeOp(node, common()->Call(desc)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 220 | } |
| 221 | |
| 222 | |
| 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; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 229 | CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( |
| 230 | zone(), f, nargs, properties, CallDescriptor::kNeedsFrameState); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 231 | Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate())); |
| 232 | Node* arity = jsgraph()->Int32Constant(nargs); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 237 | } |
| 238 | |
| 239 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 240 | void JSGenericLowering::LowerJSTypeOf(Node* node) { |
| 241 | CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
| 242 | Callable callable = CodeFactory::Typeof(isolate()); |
| 243 | ReplaceWithStubCall(node, callable, flags); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | |
| 247 | void JSGenericLowering::LowerJSToBoolean(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 248 | CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
| 249 | Callable callable = CodeFactory::ToBoolean(isolate()); |
| 250 | ReplaceWithStubCall(node, callable, |
| 251 | CallDescriptor::kPatchableCallSite | flags); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | |
| 255 | void JSGenericLowering::LowerJSToNumber(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 256 | CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 257 | Callable callable = CodeFactory::ToNumber(isolate()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 258 | ReplaceWithStubCall(node, callable, flags); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 259 | } |
| 260 | |
| 261 | |
| 262 | void JSGenericLowering::LowerJSToString(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 263 | CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
| 264 | Callable callable = CodeFactory::ToString(isolate()); |
| 265 | ReplaceWithStubCall(node, callable, flags); |
| 266 | } |
| 267 | |
| 268 | |
| 269 | void JSGenericLowering::LowerJSToName(Node* node) { |
| 270 | ReplaceWithRuntimeCall(node, Runtime::kToName); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 271 | } |
| 272 | |
| 273 | |
| 274 | void JSGenericLowering::LowerJSToObject(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 275 | CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
| 276 | Callable callable = CodeFactory::ToObject(isolate()); |
| 277 | ReplaceWithStubCall(node, callable, flags); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 278 | } |
| 279 | |
| 280 | |
| 281 | void JSGenericLowering::LowerJSLoadProperty(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 288 | } |
| 289 | |
| 290 | |
| 291 | void JSGenericLowering::LowerJSLoadNamed(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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 | |
| 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); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 323 | } |
| 324 | |
| 325 | |
| 326 | void JSGenericLowering::LowerJSStoreProperty(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 336 | } |
| 337 | |
| 338 | |
| 339 | void JSGenericLowering::LowerJSStoreNamed(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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 | |
| 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); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 375 | } |
| 376 | |
| 377 | |
| 378 | void JSGenericLowering::LowerJSDeleteProperty(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 379 | LanguageMode language_mode = OpParameter<LanguageMode>(node); |
| 380 | ReplaceWithRuntimeCall(node, is_strict(language_mode) |
| 381 | ? Runtime::kDeleteProperty_Strict |
| 382 | : Runtime::kDeleteProperty_Sloppy); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 383 | } |
| 384 | |
| 385 | |
| 386 | void JSGenericLowering::LowerJSHasProperty(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 387 | ReplaceWithRuntimeCall(node, Runtime::kHasProperty); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 388 | } |
| 389 | |
| 390 | |
| 391 | void JSGenericLowering::LowerJSInstanceOf(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 392 | CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
| 393 | Callable callable = CodeFactory::InstanceOf(isolate()); |
| 394 | ReplaceWithStubCall(node, callable, flags); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 395 | } |
| 396 | |
| 397 | |
| 398 | void JSGenericLowering::LowerJSLoadContext(Node* node) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 399 | const ContextAccess& access = ContextAccessOf(node->op()); |
| 400 | for (size_t i = 0; i < access.depth(); ++i) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 401 | node->ReplaceInput( |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 402 | 0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()), |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 403 | NodeProperties::GetValueInput(node, 0), |
| 404 | jsgraph()->Int32Constant( |
| 405 | Context::SlotOffset(Context::PREVIOUS_INDEX)), |
| 406 | NodeProperties::GetEffectInput(node), |
| 407 | graph()->start())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 408 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 409 | node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset( |
| 410 | static_cast<int>(access.index())))); |
| 411 | node->AppendInput(zone(), graph()->start()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 412 | NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 413 | } |
| 414 | |
| 415 | |
| 416 | void JSGenericLowering::LowerJSStoreContext(Node* node) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 417 | const ContextAccess& access = ContextAccessOf(node->op()); |
| 418 | for (size_t i = 0; i < access.depth(); ++i) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 419 | node->ReplaceInput( |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 420 | 0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()), |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 421 | NodeProperties::GetValueInput(node, 0), |
| 422 | jsgraph()->Int32Constant( |
| 423 | Context::SlotOffset(Context::PREVIOUS_INDEX)), |
| 424 | NodeProperties::GetEffectInput(node), |
| 425 | graph()->start())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 426 | } |
| 427 | node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1)); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 428 | node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset( |
| 429 | static_cast<int>(access.index())))); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 430 | NodeProperties::ChangeOp( |
| 431 | node, machine()->Store(StoreRepresentation(MachineRepresentation::kTagged, |
| 432 | kFullWriteBarrier))); |
| 433 | } |
| 434 | |
| 435 | |
| 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 | |
| 451 | void JSGenericLowering::LowerJSCreate(Node* node) { |
| 452 | ReplaceWithRuntimeCall(node, Runtime::kNewObject); |
| 453 | } |
| 454 | |
| 455 | |
| 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 | |
| 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 | |
| 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 | |
| 502 | void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) { |
| 503 | ReplaceWithRuntimeCall(node, Runtime::kCreateIterResultObject); |
| 504 | } |
| 505 | |
| 506 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 557 | } |
| 558 | |
| 559 | |
| 560 | void JSGenericLowering::LowerJSCallConstruct(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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)); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 577 | } |
| 578 | |
| 579 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 580 | void JSGenericLowering::LowerJSCallFunction(Node* node) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 596 | } |
| 597 | |
| 598 | |
| 599 | void JSGenericLowering::LowerJSCallRuntime(Node* node) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 600 | const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 601 | AdjustFrameStatesForCall(node); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 602 | ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 603 | } |
| 604 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 605 | |
| 606 | void JSGenericLowering::LowerJSForInDone(Node* node) { |
| 607 | ReplaceWithRuntimeCall(node, Runtime::kForInDone); |
| 608 | } |
| 609 | |
| 610 | |
| 611 | void JSGenericLowering::LowerJSForInNext(Node* node) { |
| 612 | ReplaceWithRuntimeCall(node, Runtime::kForInNext); |
| 613 | } |
| 614 | |
| 615 | |
| 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 | |
| 787 | void JSGenericLowering::LowerJSForInStep(Node* node) { |
| 788 | ReplaceWithRuntimeCall(node, Runtime::kForInStep); |
| 789 | } |
| 790 | |
| 791 | |
| 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 | |
| 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 | |
| 814 | void JSGenericLowering::LowerJSYield(Node* node) { UNIMPLEMENTED(); } |
| 815 | |
| 816 | |
| 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 | |
| 860 | Zone* JSGenericLowering::zone() const { return graph()->zone(); } |
| 861 | |
| 862 | |
| 863 | Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); } |
| 864 | |
| 865 | |
| 866 | Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); } |
| 867 | |
| 868 | |
| 869 | CommonOperatorBuilder* JSGenericLowering::common() const { |
| 870 | return jsgraph()->common(); |
| 871 | } |
| 872 | |
| 873 | |
| 874 | MachineOperatorBuilder* JSGenericLowering::machine() const { |
| 875 | return jsgraph()->machine(); |
| 876 | } |
| 877 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 878 | } // namespace compiler |
| 879 | } // namespace internal |
| 880 | } // namespace v8 |