diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-12 14:07:37 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-17 10:29:26 +0000 |
commit | ec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch) | |
tree | 25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/v8/src/interpreter/interpreter-intrinsics-generator.cc | |
parent | bb09965444b5bb20b096a291445170876225268d (diff) | |
download | qtwebengine-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.cc | 395 |
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), ¬_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(); +} + +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 |