interpreter-intrinsics.cc 10.6 KB
Newer Older
1 2 3 4 5 6
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/interpreter/interpreter-intrinsics.h"

7 8
#include "src/code-factory.h"

9 10 11 12 13 14 15 16 17
namespace v8 {
namespace internal {
namespace interpreter {

using compiler::Node;

#define __ assembler_->

IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler)
18 19 20
    : isolate_(assembler->isolate()),
      zone_(assembler->zone()),
      assembler_(assembler) {}
21

22
// static
23 24 25 26 27 28 29 30 31 32 33
bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) {
  switch (function_id) {
#define SUPPORTED(name, lower_case, count) case Runtime::kInline##name:
    INTRINSICS_LIST(SUPPORTED)
    return true;
#undef SUPPORTED
    default:
      return false;
  }
}

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
// static
IntrinsicsHelper::IntrinsicId IntrinsicsHelper::FromRuntimeId(
    Runtime::FunctionId function_id) {
  switch (function_id) {
#define TO_RUNTIME_ID(name, lower_case, count) \
  case Runtime::kInline##name:                 \
    return IntrinsicId::k##name;
    INTRINSICS_LIST(TO_RUNTIME_ID)
#undef TO_RUNTIME_ID
    default:
      UNREACHABLE();
      return static_cast<IntrinsicsHelper::IntrinsicId>(-1);
  }
}

// static
Runtime::FunctionId IntrinsicsHelper::ToRuntimeId(
    IntrinsicsHelper::IntrinsicId intrinsic_id) {
  switch (intrinsic_id) {
#define TO_INTRINSIC_ID(name, lower_case, count) \
  case IntrinsicId::k##name:                     \
    return Runtime::kInline##name;
    INTRINSICS_LIST(TO_INTRINSIC_ID)
#undef TO_INTRINSIC_ID
    default:
      UNREACHABLE();
      return static_cast<Runtime::FunctionId>(-1);
  }
}

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context,
                                        Node* first_arg_reg, Node* arg_count) {
  InterpreterAssembler::Label abort(assembler_), end(assembler_);
  InterpreterAssembler::Variable result(assembler_,
                                        MachineRepresentation::kTagged);

#define MAKE_LABEL(name, lower_case, count) \
  InterpreterAssembler::Label lower_case(assembler_);
  INTRINSICS_LIST(MAKE_LABEL)
#undef MAKE_LABEL

#define LABEL_POINTER(name, lower_case, count) &lower_case,
  InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)};
#undef LABEL_POINTER

#define CASE(name, lower_case, count) \
80
  static_cast<int32_t>(IntrinsicId::k##name),
81 82 83 84 85 86
  int32_t cases[] = {INTRINSICS_LIST(CASE)};
#undef CASE

  __ Switch(function_id, &abort, cases, labels, arraysize(cases));
#define HANDLE_CASE(name, lower_case, expected_arg_count)   \
  __ Bind(&lower_case);                                     \
87
  if (FLAG_debug_code && expected_arg_count >= 0) {         \
88 89
    AbortIfArgCountMismatch(expected_arg_count, arg_count); \
  }                                                         \
90
  result.Bind(name(first_arg_reg, arg_count, context));     \
91 92 93 94 95
  __ Goto(&end);
  INTRINSICS_LIST(HANDLE_CASE)
#undef HANDLE_CASE

  __ Bind(&abort);
96 97 98 99 100
  {
    __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic);
    result.Bind(__ UndefinedConstant());
    __ Goto(&end);
  }
101 102 103 104 105

  __ Bind(&end);
  return result.value();
}

106
Node* IntrinsicsHelper::CompareInstanceType(Node* object, int type,
107
                                            InstanceTypeCompareMode mode) {
108
  Node* instance_type = __ LoadInstanceType(object);
109 110

  if (mode == kInstanceTypeEqual) {
111
    return __ Word32Equal(instance_type, __ Int32Constant(type));
112 113
  } else {
    DCHECK(mode == kInstanceTypeGreaterThanOrEqual);
114
    return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
115
  }
116 117 118 119 120
}

Node* IntrinsicsHelper::IsInstanceType(Node* input, int type) {
  InterpreterAssembler::Variable return_value(assembler_,
                                              MachineRepresentation::kTagged);
121
  // TODO(ishell): Use Select here.
122 123
  InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_),
      return_false(assembler_), end(assembler_);
124
  Node* arg = __ LoadRegister(input);
125
  __ GotoIf(__ TaggedIsSmi(arg), &return_false);
126

127 128 129 130
  Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual);
  __ Branch(condition, &return_true, &return_false);

  __ Bind(&return_true);
131
  {
132
    return_value.Bind(__ BooleanConstant(true));
133 134 135
    __ Goto(&end);
  }

136
  __ Bind(&return_false);
137
  {
138
    return_value.Bind(__ BooleanConstant(false));
139 140
    __ Goto(&end);
  }
141 142 143 144 145

  __ Bind(&end);
  return return_value.value();
}

146 147
Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count,
                                     Node* context) {
148 149
  // TODO(ishell): Use Select here.
  // TODO(ishell): Use CSA::IsJSReceiverInstanceType here.
150 151
  InterpreterAssembler::Variable return_value(assembler_,
                                              MachineRepresentation::kTagged);
152
  InterpreterAssembler::Label return_true(assembler_), return_false(assembler_),
153 154
      end(assembler_);

155
  Node* arg = __ LoadRegister(input);
156
  __ GotoIf(__ TaggedIsSmi(arg), &return_false);
157

158 159 160 161 162 163
  STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
  Node* condition = CompareInstanceType(arg, FIRST_JS_RECEIVER_TYPE,
                                        kInstanceTypeGreaterThanOrEqual);
  __ Branch(condition, &return_true, &return_false);

  __ Bind(&return_true);
164
  {
165
    return_value.Bind(__ BooleanConstant(true));
166 167
    __ Goto(&end);
  }
168

169
  __ Bind(&return_false);
170
  {
171
    return_value.Bind(__ BooleanConstant(false));
172 173
    __ Goto(&end);
  }
174 175 176 177 178

  __ Bind(&end);
  return return_value.value();
}

179
Node* IntrinsicsHelper::IsArray(Node* input, Node* arg_count, Node* context) {
180 181 182 183 184 185 186 187 188 189 190 191 192
  return IsInstanceType(input, JS_ARRAY_TYPE);
}

Node* IntrinsicsHelper::IsJSProxy(Node* input, Node* arg_count, Node* context) {
  return IsInstanceType(input, JS_PROXY_TYPE);
}

Node* IntrinsicsHelper::IsTypedArray(Node* input, Node* arg_count,
                                     Node* context) {
  return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
}

Node* IntrinsicsHelper::IsSmi(Node* input, Node* arg_count, Node* context) {
193
  // TODO(ishell): Use SelectBooleanConstant here.
194 195 196 197
  InterpreterAssembler::Variable return_value(assembler_,
                                              MachineRepresentation::kTagged);
  InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
      end(assembler_);
198

199 200
  Node* arg = __ LoadRegister(input);

201
  __ Branch(__ TaggedIsSmi(arg), &if_smi, &if_not_smi);
202
  __ Bind(&if_smi);
203 204 205 206
  {
    return_value.Bind(__ BooleanConstant(true));
    __ Goto(&end);
  }
207 208

  __ Bind(&if_not_smi);
209 210 211 212
  {
    return_value.Bind(__ BooleanConstant(false));
    __ Goto(&end);
  }
213 214 215 216 217

  __ Bind(&end);
  return return_value.value();
}

218 219 220
Node* IntrinsicsHelper::IntrinsicAsStubCall(Node* args_reg, Node* context,
                                            Callable const& callable) {
  int param_count = callable.descriptor().GetParameterCount();
221 222 223 224
  int input_count = param_count + 2;  // +2 for target and context
  Node** args = zone()->NewArray<Node*>(input_count);
  int index = 0;
  args[index++] = __ HeapConstant(callable.code());
225
  for (int i = 0; i < param_count; i++) {
226
    args[index++] = __ LoadRegister(args_reg);
227 228
    args_reg = __ NextRegister(args_reg);
  }
229 230
  args[index++] = context;
  return __ CallStubN(callable.descriptor(), 1, input_count, args);
231 232
}

233 234 235 236 237 238
Node* IntrinsicsHelper::CreateIterResultObject(Node* input, Node* arg_count,
                                               Node* context) {
  return IntrinsicAsStubCall(input, context,
                             CodeFactory::CreateIterResultObject(isolate()));
}

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count,
                                    Node* context) {
  return IntrinsicAsStubCall(input, context,
                             CodeFactory::HasProperty(isolate()));
}

Node* IntrinsicsHelper::NumberToString(Node* input, Node* arg_count,
                                       Node* context) {
  return IntrinsicAsStubCall(input, context,
                             CodeFactory::NumberToString(isolate()));
}

Node* IntrinsicsHelper::RegExpExec(Node* input, Node* arg_count,
                                   Node* context) {
  return IntrinsicAsStubCall(input, context,
                             CodeFactory::RegExpExec(isolate()));
}

Node* IntrinsicsHelper::SubString(Node* input, Node* arg_count, Node* context) {
  return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate()));
}

Node* IntrinsicsHelper::ToString(Node* input, Node* arg_count, Node* context) {
  return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate()));
}

Node* IntrinsicsHelper::ToLength(Node* input, Node* arg_count, Node* context) {
  return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate()));
}

Node* IntrinsicsHelper::ToInteger(Node* input, Node* arg_count, Node* context) {
  return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate()));
}

Node* IntrinsicsHelper::ToNumber(Node* input, Node* arg_count, Node* context) {
  return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate()));
}

Node* IntrinsicsHelper::ToObject(Node* input, Node* arg_count, Node* context) {
  return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate()));
}

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
Node* IntrinsicsHelper::Call(Node* args_reg, Node* arg_count, Node* context) {
  // First argument register contains the function target.
  Node* function = __ LoadRegister(args_reg);

  // Receiver is the second runtime call argument.
  Node* receiver_reg = __ NextRegister(args_reg);
  Node* receiver_arg = __ RegisterLocation(receiver_reg);

  // Subtract function and receiver from arg count.
  Node* function_and_receiver_count = __ Int32Constant(2);
  Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count);

  if (FLAG_debug_code) {
    InterpreterAssembler::Label arg_count_positive(assembler_);
    Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0));
    __ GotoUnless(comparison, &arg_count_positive);
    __ Abort(kWrongArgumentCountForInvokeIntrinsic);
    __ Goto(&arg_count_positive);
    __ Bind(&arg_count_positive);
  }

  Node* result = __ CallJS(function, context, receiver_arg, target_args_count,
                           TailCallMode::kDisallow);
  return result;
}

307 308
Node* IntrinsicsHelper::ClassOf(Node* args_reg, Node* arg_count,
                                Node* context) {
309 310
  Node* value = __ LoadRegister(args_reg);
  return __ ClassOf(value);
311 312
}

313
void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) {
314
  InterpreterAssembler::Label match(assembler_);
315
  Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
316
  __ GotoIf(comparison, &match);
317
  __ Abort(kWrongArgumentCountForInvokeIntrinsic);
318
  __ Goto(&match);
319 320 321 322 323 324
  __ Bind(&match);
}

}  // namespace interpreter
}  // namespace internal
}  // namespace v8