[interpreter] Split out intrinsics generation
This frees up the InterpreterAssembler for no longer being linked into the main library. BUG=v8:6055 Review-Url: https://codereview.chromium.org/2759093004 Cr-Commit-Position: refs/heads/master@{#43979}
This commit is contained in:
parent
0feed731d0
commit
c8a727dec2
6
BUILD.gn
6
BUILD.gn
@ -939,8 +939,12 @@ v8_source_set("v8_builtins_generators") {
|
||||
"src/ic/accessor-assembler.h",
|
||||
"src/ic/keyed-store-generic.cc",
|
||||
"src/ic/keyed-store-generic.h",
|
||||
"src/interpreter/interpreter-assembler.cc",
|
||||
"src/interpreter/interpreter-assembler.h",
|
||||
"src/interpreter/interpreter-generator.cc",
|
||||
"src/interpreter/interpreter-generator.h",
|
||||
"src/interpreter/interpreter-intrinsics-generator.cc",
|
||||
"src/interpreter/interpreter-intrinsics-generator.h",
|
||||
]
|
||||
|
||||
if (v8_current_cpu == "x86") {
|
||||
@ -1642,8 +1646,6 @@ v8_source_set("v8_base") {
|
||||
"src/interpreter/control-flow-builders.h",
|
||||
"src/interpreter/handler-table-builder.cc",
|
||||
"src/interpreter/handler-table-builder.h",
|
||||
"src/interpreter/interpreter-assembler.cc",
|
||||
"src/interpreter/interpreter-assembler.h",
|
||||
"src/interpreter/interpreter-generator.h",
|
||||
"src/interpreter/interpreter-intrinsics.cc",
|
||||
"src/interpreter/interpreter-intrinsics.h",
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "src/interpreter/bytecode-flags.h"
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "src/interpreter/interpreter-assembler.h"
|
||||
#include "src/interpreter/interpreter-intrinsics.h"
|
||||
#include "src/interpreter/interpreter-intrinsics-generator.h"
|
||||
#include "src/objects-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -2123,9 +2123,8 @@ void InterpreterGenerator::DoInvokeIntrinsic(InterpreterAssembler* assembler) {
|
||||
Node* first_arg_reg = __ BytecodeOperandReg(1);
|
||||
Node* arg_count = __ BytecodeOperandCount(2);
|
||||
Node* context = __ GetContext();
|
||||
IntrinsicsHelper helper(assembler);
|
||||
Node* result =
|
||||
helper.InvokeIntrinsic(function_id, context, first_arg_reg, arg_count);
|
||||
Node* result = GenerateInvokeIntrinsic(assembler, function_id, context,
|
||||
first_arg_reg, arg_count);
|
||||
__ SetAccumulator(result);
|
||||
__ Dispatch();
|
||||
}
|
||||
|
364
src/interpreter/interpreter-intrinsics-generator.cc
Normal file
364
src/interpreter/interpreter-intrinsics-generator.cc
Normal file
@ -0,0 +1,364 @@
|
||||
// Copyright 2017 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-generator.h"
|
||||
|
||||
#include "src/allocation.h"
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/code-factory.h"
|
||||
#include "src/frames.h"
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "src/interpreter/interpreter-assembler.h"
|
||||
#include "src/interpreter/interpreter-intrinsics.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
using compiler::Node;
|
||||
|
||||
class IntrinsicsGenerator {
|
||||
public:
|
||||
explicit IntrinsicsGenerator(InterpreterAssembler* assembler)
|
||||
: isolate_(assembler->isolate()),
|
||||
zone_(assembler->zone()),
|
||||
assembler_(assembler) {}
|
||||
|
||||
Node* InvokeIntrinsic(Node* function_id, Node* context, Node* first_arg_reg,
|
||||
Node* arg_count);
|
||||
|
||||
private:
|
||||
enum InstanceTypeCompareMode {
|
||||
kInstanceTypeEqual,
|
||||
kInstanceTypeGreaterThanOrEqual
|
||||
};
|
||||
|
||||
Node* IsInstanceType(Node* input, int type);
|
||||
Node* CompareInstanceType(Node* map, int type, InstanceTypeCompareMode mode);
|
||||
Node* IntrinsicAsStubCall(Node* input, Node* context,
|
||||
Callable const& callable);
|
||||
void AbortIfArgCountMismatch(int expected, compiler::Node* actual);
|
||||
|
||||
#define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \
|
||||
Node* name(Node* input, Node* arg_count, Node* context);
|
||||
INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER)
|
||||
#undef DECLARE_INTRINSIC_HELPER
|
||||
|
||||
Isolate* isolate() { return isolate_; }
|
||||
Zone* zone() { return zone_; }
|
||||
|
||||
Isolate* isolate_;
|
||||
Zone* zone_;
|
||||
InterpreterAssembler* assembler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(IntrinsicsGenerator);
|
||||
};
|
||||
|
||||
Node* GenerateInvokeIntrinsic(InterpreterAssembler* assembler,
|
||||
Node* function_id, Node* context,
|
||||
Node* first_arg_reg, Node* arg_count) {
|
||||
IntrinsicsGenerator generator(assembler);
|
||||
return generator.InvokeIntrinsic(function_id, context, first_arg_reg,
|
||||
arg_count);
|
||||
}
|
||||
|
||||
#define __ assembler_->
|
||||
|
||||
Node* IntrinsicsGenerator::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) \
|
||||
static_cast<int32_t>(IntrinsicsHelper::IntrinsicId::k##name),
|
||||
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); \
|
||||
if (FLAG_debug_code && expected_arg_count >= 0) { \
|
||||
AbortIfArgCountMismatch(expected_arg_count, arg_count); \
|
||||
} \
|
||||
result.Bind(name(first_arg_reg, arg_count, context)); \
|
||||
__ Goto(&end);
|
||||
INTRINSICS_LIST(HANDLE_CASE)
|
||||
#undef HANDLE_CASE
|
||||
|
||||
__ Bind(&abort);
|
||||
{
|
||||
__ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic);
|
||||
result.Bind(__ UndefinedConstant());
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&end);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::CompareInstanceType(Node* object, int type,
|
||||
InstanceTypeCompareMode mode) {
|
||||
Node* instance_type = __ LoadInstanceType(object);
|
||||
|
||||
if (mode == kInstanceTypeEqual) {
|
||||
return __ Word32Equal(instance_type, __ Int32Constant(type));
|
||||
} else {
|
||||
DCHECK(mode == kInstanceTypeGreaterThanOrEqual);
|
||||
return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
|
||||
}
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::IsInstanceType(Node* input, int type) {
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
// TODO(ishell): Use Select here.
|
||||
InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_),
|
||||
return_false(assembler_), end(assembler_);
|
||||
Node* arg = __ LoadRegister(input);
|
||||
__ GotoIf(__ TaggedIsSmi(arg), &return_false);
|
||||
|
||||
Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual);
|
||||
__ Branch(condition, &return_true, &return_false);
|
||||
|
||||
__ Bind(&return_true);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(true));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&return_false);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::IsJSReceiver(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
// TODO(ishell): Use Select here.
|
||||
// TODO(ishell): Use CSA::IsJSReceiverInstanceType here.
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
InterpreterAssembler::Label return_true(assembler_), return_false(assembler_),
|
||||
end(assembler_);
|
||||
|
||||
Node* arg = __ LoadRegister(input);
|
||||
__ GotoIf(__ TaggedIsSmi(arg), &return_false);
|
||||
|
||||
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);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(true));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&return_false);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::IsArray(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IsInstanceType(input, JS_ARRAY_TYPE);
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::IsJSProxy(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IsInstanceType(input, JS_PROXY_TYPE);
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::IsTypedArray(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::IsSmi(Node* input, Node* arg_count, Node* context) {
|
||||
// TODO(ishell): Use SelectBooleanConstant here.
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
|
||||
end(assembler_);
|
||||
|
||||
Node* arg = __ LoadRegister(input);
|
||||
|
||||
__ Branch(__ TaggedIsSmi(arg), &if_smi, &if_not_smi);
|
||||
__ Bind(&if_smi);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(true));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&if_not_smi);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::IntrinsicAsStubCall(Node* args_reg, Node* context,
|
||||
Callable const& callable) {
|
||||
int param_count = callable.descriptor().GetParameterCount();
|
||||
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());
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
args[index++] = __ LoadRegister(args_reg);
|
||||
args_reg = __ NextRegister(args_reg);
|
||||
}
|
||||
args[index++] = context;
|
||||
return __ CallStubN(callable.descriptor(), 1, input_count, args);
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::CreateIterResultObject(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context,
|
||||
CodeFactory::CreateIterResultObject(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::HasProperty(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context,
|
||||
CodeFactory::HasProperty(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::SubString(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::ToString(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::ToLength(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::ToInteger(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::ToNumber(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::ToObject(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::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));
|
||||
__ GotoIfNot(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;
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::ClassOf(Node* args_reg, Node* arg_count,
|
||||
Node* context) {
|
||||
Node* value = __ LoadRegister(args_reg);
|
||||
return __ ClassOf(value);
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::CreateAsyncFromSyncIterator(Node* args_reg,
|
||||
Node* arg_count,
|
||||
Node* context) {
|
||||
InterpreterAssembler::Label not_receiver(
|
||||
assembler_, InterpreterAssembler::Label::kDeferred);
|
||||
InterpreterAssembler::Label done(assembler_);
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
|
||||
Node* sync_iterator = __ LoadRegister(args_reg);
|
||||
|
||||
__ GotoIf(__ TaggedIsSmi(sync_iterator), ¬_receiver);
|
||||
__ GotoIfNot(__ IsJSReceiver(sync_iterator), ¬_receiver);
|
||||
|
||||
Node* const native_context = __ LoadNativeContext(context);
|
||||
Node* const map = __ LoadContextElement(
|
||||
native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
|
||||
Node* const iterator = __ AllocateJSObjectFromMap(map);
|
||||
|
||||
__ StoreObjectFieldNoWriteBarrier(
|
||||
iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
|
||||
|
||||
return_value.Bind(iterator);
|
||||
__ Goto(&done);
|
||||
|
||||
__ Bind(¬_receiver);
|
||||
{
|
||||
return_value.Bind(
|
||||
__ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
|
||||
|
||||
// Unreachable due to the Throw in runtime call.
|
||||
__ Goto(&done);
|
||||
}
|
||||
|
||||
__ Bind(&done);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
void IntrinsicsGenerator::AbortIfArgCountMismatch(int expected, Node* actual) {
|
||||
InterpreterAssembler::Label match(assembler_);
|
||||
Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
|
||||
__ GotoIf(comparison, &match);
|
||||
__ Abort(kWrongArgumentCountForInvokeIntrinsic);
|
||||
__ Goto(&match);
|
||||
__ Bind(&match);
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
29
src/interpreter/interpreter-intrinsics-generator.h
Normal file
29
src/interpreter/interpreter-intrinsics-generator.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#ifndef V8_INTERPRETER_INTERPRETER_INTRINSICS_GENERATOR_H_
|
||||
#define V8_INTERPRETER_INTERPRETER_INTRINSICS_GENERATOR_H_
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace compiler {
|
||||
class Node;
|
||||
} // namespace compiler
|
||||
|
||||
namespace interpreter {
|
||||
|
||||
class InterpreterAssembler;
|
||||
|
||||
extern compiler::Node* GenerateInvokeIntrinsic(InterpreterAssembler* assembler,
|
||||
compiler::Node* function_id,
|
||||
compiler::Node* context,
|
||||
compiler::Node* first_arg_reg,
|
||||
compiler::Node* arg_count);
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_INTERPRETER_INTERPRETER_INTRINSICS_GENERATOR_H_
|
@ -4,22 +4,12 @@
|
||||
|
||||
#include "src/interpreter/interpreter-intrinsics.h"
|
||||
|
||||
#include "src/code-factory.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/base/logging.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
using compiler::Node;
|
||||
|
||||
#define __ assembler_->
|
||||
|
||||
IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler)
|
||||
: isolate_(assembler->isolate()),
|
||||
zone_(assembler->zone()),
|
||||
assembler_(assembler) {}
|
||||
|
||||
// static
|
||||
bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) {
|
||||
switch (function_id) {
|
||||
@ -62,290 +52,6 @@ Runtime::FunctionId IntrinsicsHelper::ToRuntimeId(
|
||||
}
|
||||
}
|
||||
|
||||
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) \
|
||||
static_cast<int32_t>(IntrinsicId::k##name),
|
||||
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); \
|
||||
if (FLAG_debug_code && expected_arg_count >= 0) { \
|
||||
AbortIfArgCountMismatch(expected_arg_count, arg_count); \
|
||||
} \
|
||||
result.Bind(name(first_arg_reg, arg_count, context)); \
|
||||
__ Goto(&end);
|
||||
INTRINSICS_LIST(HANDLE_CASE)
|
||||
#undef HANDLE_CASE
|
||||
|
||||
__ Bind(&abort);
|
||||
{
|
||||
__ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic);
|
||||
result.Bind(__ UndefinedConstant());
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&end);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::CompareInstanceType(Node* object, int type,
|
||||
InstanceTypeCompareMode mode) {
|
||||
Node* instance_type = __ LoadInstanceType(object);
|
||||
|
||||
if (mode == kInstanceTypeEqual) {
|
||||
return __ Word32Equal(instance_type, __ Int32Constant(type));
|
||||
} else {
|
||||
DCHECK(mode == kInstanceTypeGreaterThanOrEqual);
|
||||
return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
|
||||
}
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::IsInstanceType(Node* input, int type) {
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
// TODO(ishell): Use Select here.
|
||||
InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_),
|
||||
return_false(assembler_), end(assembler_);
|
||||
Node* arg = __ LoadRegister(input);
|
||||
__ GotoIf(__ TaggedIsSmi(arg), &return_false);
|
||||
|
||||
Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual);
|
||||
__ Branch(condition, &return_true, &return_false);
|
||||
|
||||
__ Bind(&return_true);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(true));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&return_false);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
// TODO(ishell): Use Select here.
|
||||
// TODO(ishell): Use CSA::IsJSReceiverInstanceType here.
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
InterpreterAssembler::Label return_true(assembler_), return_false(assembler_),
|
||||
end(assembler_);
|
||||
|
||||
Node* arg = __ LoadRegister(input);
|
||||
__ GotoIf(__ TaggedIsSmi(arg), &return_false);
|
||||
|
||||
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);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(true));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&return_false);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::IsArray(Node* input, Node* arg_count, Node* context) {
|
||||
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) {
|
||||
// TODO(ishell): Use SelectBooleanConstant here.
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
|
||||
end(assembler_);
|
||||
|
||||
Node* arg = __ LoadRegister(input);
|
||||
|
||||
__ Branch(__ TaggedIsSmi(arg), &if_smi, &if_not_smi);
|
||||
__ Bind(&if_smi);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(true));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&if_not_smi);
|
||||
{
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
}
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::IntrinsicAsStubCall(Node* args_reg, Node* context,
|
||||
Callable const& callable) {
|
||||
int param_count = callable.descriptor().GetParameterCount();
|
||||
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());
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
args[index++] = __ LoadRegister(args_reg);
|
||||
args_reg = __ NextRegister(args_reg);
|
||||
}
|
||||
args[index++] = context;
|
||||
return __ CallStubN(callable.descriptor(), 1, input_count, args);
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::CreateIterResultObject(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context,
|
||||
CodeFactory::CreateIterResultObject(isolate()));
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
return IntrinsicAsStubCall(input, context,
|
||||
CodeFactory::HasProperty(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()));
|
||||
}
|
||||
|
||||
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));
|
||||
__ GotoIfNot(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;
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::ClassOf(Node* args_reg, Node* arg_count,
|
||||
Node* context) {
|
||||
Node* value = __ LoadRegister(args_reg);
|
||||
return __ ClassOf(value);
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::CreateAsyncFromSyncIterator(Node* args_reg,
|
||||
Node* arg_count,
|
||||
Node* context) {
|
||||
InterpreterAssembler::Label not_receiver(
|
||||
assembler_, InterpreterAssembler::Label::kDeferred);
|
||||
InterpreterAssembler::Label done(assembler_);
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
|
||||
Node* sync_iterator = __ LoadRegister(args_reg);
|
||||
|
||||
__ GotoIf(__ TaggedIsSmi(sync_iterator), ¬_receiver);
|
||||
__ GotoIfNot(__ IsJSReceiver(sync_iterator), ¬_receiver);
|
||||
|
||||
Node* const native_context = __ LoadNativeContext(context);
|
||||
Node* const map = __ LoadContextElement(
|
||||
native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
|
||||
Node* const iterator = __ AllocateJSObjectFromMap(map);
|
||||
|
||||
__ StoreObjectFieldNoWriteBarrier(
|
||||
iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
|
||||
|
||||
return_value.Bind(iterator);
|
||||
__ Goto(&done);
|
||||
|
||||
__ Bind(¬_receiver);
|
||||
{
|
||||
return_value.Bind(
|
||||
__ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
|
||||
|
||||
// Unreachable due to the Throw in runtime call.
|
||||
__ Goto(&done);
|
||||
}
|
||||
|
||||
__ Bind(&done);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) {
|
||||
InterpreterAssembler::Label match(assembler_);
|
||||
Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
|
||||
__ GotoIf(comparison, &match);
|
||||
__ Abort(kWrongArgumentCountForInvokeIntrinsic);
|
||||
__ Goto(&match);
|
||||
__ Bind(&match);
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -5,20 +5,10 @@
|
||||
#ifndef V8_INTERPRETER_INTERPRETER_INTRINSICS_H_
|
||||
#define V8_INTERPRETER_INTERPRETER_INTRINSICS_H_
|
||||
|
||||
#include "src/allocation.h"
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/frames.h"
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "src/interpreter/interpreter-assembler.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace compiler {
|
||||
class Node;
|
||||
} // namespace compiler
|
||||
|
||||
namespace interpreter {
|
||||
|
||||
// List of supported intrisics, with upper case name, lower case name and
|
||||
@ -51,45 +41,12 @@ class IntrinsicsHelper {
|
||||
};
|
||||
STATIC_ASSERT(static_cast<uint32_t>(IntrinsicId::kIdCount) <= kMaxUInt8);
|
||||
|
||||
explicit IntrinsicsHelper(InterpreterAssembler* assembler);
|
||||
|
||||
compiler::Node* InvokeIntrinsic(compiler::Node* function_id,
|
||||
compiler::Node* context,
|
||||
compiler::Node* first_arg_reg,
|
||||
compiler::Node* arg_count);
|
||||
|
||||
static bool IsSupported(Runtime::FunctionId function_id);
|
||||
static IntrinsicId FromRuntimeId(Runtime::FunctionId function_id);
|
||||
static Runtime::FunctionId ToRuntimeId(IntrinsicId intrinsic_id);
|
||||
|
||||
private:
|
||||
enum InstanceTypeCompareMode {
|
||||
kInstanceTypeEqual,
|
||||
kInstanceTypeGreaterThanOrEqual
|
||||
};
|
||||
|
||||
compiler::Node* IsInstanceType(compiler::Node* input, int type);
|
||||
compiler::Node* CompareInstanceType(compiler::Node* map, int type,
|
||||
InstanceTypeCompareMode mode);
|
||||
compiler::Node* IntrinsicAsStubCall(compiler::Node* input,
|
||||
compiler::Node* context,
|
||||
Callable const& callable);
|
||||
void AbortIfArgCountMismatch(int expected, compiler::Node* actual);
|
||||
|
||||
#define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \
|
||||
compiler::Node* name(compiler::Node* input, compiler::Node* arg_count, \
|
||||
compiler::Node* context);
|
||||
INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER)
|
||||
#undef DECLARE_INTRINSIC_HELPER
|
||||
|
||||
Isolate* isolate() { return isolate_; }
|
||||
Zone* zone() { return zone_; }
|
||||
|
||||
Isolate* isolate_;
|
||||
Zone* zone_;
|
||||
InterpreterAssembler* assembler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(IntrinsicsHelper);
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(IntrinsicsHelper);
|
||||
};
|
||||
|
||||
} // namespace interpreter
|
||||
|
@ -1065,6 +1065,8 @@
|
||||
'interpreter/interpreter-generator.h',
|
||||
'interpreter/interpreter-intrinsics.cc',
|
||||
'interpreter/interpreter-intrinsics.h',
|
||||
'interpreter/interpreter-intrinsics-generator.cc',
|
||||
'interpreter/interpreter-intrinsics-generator.h',
|
||||
'isolate-inl.h',
|
||||
'isolate.cc',
|
||||
'isolate.h',
|
||||
|
Loading…
Reference in New Issue
Block a user