summaryrefslogtreecommitdiff
path: root/chromium/v8/src/interpreter/interpreter-intrinsics-generator.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-12 14:07:37 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 10:29:26 +0000
commitec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch)
tree25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/v8/src/interpreter/interpreter-intrinsics-generator.cc
parentbb09965444b5bb20b096a291445170876225268d (diff)
downloadqtwebengine-chromium-ec02ee4181c49b61fce1c8fb99292dbb8139cc90.tar.gz
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/v8/src/interpreter/interpreter-intrinsics-generator.cc')
-rw-r--r--chromium/v8/src/interpreter/interpreter-intrinsics-generator.cc395
1 files changed, 395 insertions, 0 deletions
diff --git a/chromium/v8/src/interpreter/interpreter-intrinsics-generator.cc b/chromium/v8/src/interpreter/interpreter-intrinsics-generator.cc
new file mode 100644
index 00000000000..bdd079ab841
--- /dev/null
+++ b/chromium/v8/src/interpreter/interpreter-intrinsics-generator.cc
@@ -0,0 +1,395 @@
+// 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);
+ Node* IntrinsicAsBuiltinCall(Node* input, Node* context, Builtins::Name name);
+ 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::IntrinsicAsBuiltinCall(Node* input, Node* context,
+ Builtins::Name name) {
+ Callable callable = Builtins::CallableFor(isolate_, name);
+ return IntrinsicAsStubCall(input, context, callable);
+}
+
+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,
+ ConvertReceiverMode::kAny, 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), &not_receiver);
+ __ GotoIfNot(__ IsJSReceiver(sync_iterator), &not_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(&not_receiver);
+ {
+ return_value.Bind(
+ __ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
+
+ // Unreachable due to the Throw in runtime call.
+ __ Goto(&done);
+ }
+
+ __ Bind(&done);
+ return return_value.value();
+}
+
+Node* IntrinsicsGenerator::AsyncGeneratorGetAwaitInputOrDebugPos(
+ Node* args_reg, Node* arg_count, Node* context) {
+ Node* generator = __ LoadRegister(args_reg);
+ CSA_SLOW_ASSERT(assembler_, __ HasInstanceType(
+ generator, JS_ASYNC_GENERATOR_OBJECT_TYPE));
+
+ Node* const value = __ LoadObjectField(
+ generator, JSAsyncGeneratorObject::kAwaitInputOrDebugPosOffset);
+
+ return value;
+}
+
+Node* IntrinsicsGenerator::AsyncGeneratorReject(Node* input, Node* arg_count,
+ Node* context) {
+ return IntrinsicAsBuiltinCall(input, context,
+ Builtins::kAsyncGeneratorReject);
+}
+
+Node* IntrinsicsGenerator::AsyncGeneratorResolve(Node* input, Node* arg_count,
+ Node* context) {
+ return IntrinsicAsBuiltinCall(input, context,
+ Builtins::kAsyncGeneratorResolve);
+}
+
+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