// 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/builtins/builtins.h" #include "src/codegen/code-factory.h" #include "src/execution/frames.h" #include "src/heap/factory-inl.h" #include "src/interpreter/bytecodes.h" #include "src/interpreter/interpreter-assembler.h" #include "src/interpreter/interpreter-intrinsics.h" #include "src/objects/js-generator.h" #include "src/objects/objects-inl.h" #include "src/objects/source-text-module.h" #include "src/utils/allocation.h" namespace v8 { namespace internal { namespace interpreter { class IntrinsicsGenerator { public: explicit IntrinsicsGenerator(InterpreterAssembler* assembler) : isolate_(assembler->isolate()), zone_(assembler->zone()), assembler_(assembler) {} IntrinsicsGenerator(const IntrinsicsGenerator&) = delete; IntrinsicsGenerator& operator=(const IntrinsicsGenerator&) = delete; TNode InvokeIntrinsic( TNode function_id, TNode context, const InterpreterAssembler::RegListNodePair& args); private: TNode IntrinsicAsBuiltinCall( const InterpreterAssembler::RegListNodePair& args, TNode context, Builtin name, int arg_count); void AbortIfArgCountMismatch(int expected, TNode actual); #define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \ TNode name(const InterpreterAssembler::RegListNodePair& args, \ TNode context, int arg_count); INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER) #undef DECLARE_INTRINSIC_HELPER Isolate* isolate() { return isolate_; } Zone* zone() { return zone_; } Factory* factory() { return isolate()->factory(); } Isolate* isolate_; Zone* zone_; InterpreterAssembler* assembler_; }; TNode GenerateInvokeIntrinsic( InterpreterAssembler* assembler, TNode function_id, TNode context, const InterpreterAssembler::RegListNodePair& args) { IntrinsicsGenerator generator(assembler); return generator.InvokeIntrinsic(function_id, context, args); } #define __ assembler_-> TNode IntrinsicsGenerator::InvokeIntrinsic( TNode function_id, TNode context, const InterpreterAssembler::RegListNodePair& args) { InterpreterAssembler::Label abort(assembler_), end(assembler_); InterpreterAssembler::TVariable result(assembler_); #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(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, args.reg_count()); \ } \ TNode value = name(args, context, expected_arg_count); \ if (value) { \ result = value; \ __ Goto(&end); \ } \ } INTRINSICS_LIST(HANDLE_CASE) #undef HANDLE_CASE __ BIND(&abort); { __ Abort(AbortReason::kUnexpectedFunctionIDForInvokeIntrinsic); result = __ UndefinedConstant(); __ Goto(&end); } __ BIND(&end); return result.value(); } TNode IntrinsicsGenerator::IntrinsicAsBuiltinCall( const InterpreterAssembler::RegListNodePair& args, TNode context, Builtin name, int arg_count) { Callable callable = Builtins::CallableFor(isolate_, name); switch (arg_count) { case 1: return __ CallStub(callable, context, __ LoadRegisterFromRegisterList(args, 0)); case 2: return __ CallStub(callable, context, __ LoadRegisterFromRegisterList(args, 0), __ LoadRegisterFromRegisterList(args, 1)); case 3: return __ CallStub(callable, context, __ LoadRegisterFromRegisterList(args, 0), __ LoadRegisterFromRegisterList(args, 1), __ LoadRegisterFromRegisterList(args, 2)); default: UNREACHABLE(); } } TNode IntrinsicsGenerator::CopyDataProperties( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kCopyDataProperties, arg_count); } TNode IntrinsicsGenerator::CreateIterResultObject( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kCreateIterResultObject, arg_count); } TNode IntrinsicsGenerator::CreateAsyncFromSyncIterator( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { TNode sync_iterator = __ LoadRegisterFromRegisterList(args, 0); return __ CreateAsyncFromSyncIterator(context, sync_iterator); } TNode IntrinsicsGenerator::CreateJSGeneratorObject( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kCreateGeneratorObject, arg_count); } TNode IntrinsicsGenerator::GeneratorGetResumeMode( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { TNode generator = __ CAST(__ LoadRegisterFromRegisterList(args, 0)); const TNode value = __ LoadObjectField(generator, JSGeneratorObject::kResumeModeOffset); return value; } TNode IntrinsicsGenerator::GeneratorClose( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { TNode generator = __ CAST(__ LoadRegisterFromRegisterList(args, 0)); __ StoreObjectFieldNoWriteBarrier( generator, JSGeneratorObject::kContinuationOffset, __ SmiConstant(JSGeneratorObject::kGeneratorClosed)); return __ UndefinedConstant(); } TNode IntrinsicsGenerator::GetImportMetaObject( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return __ GetImportMetaObject(context); } TNode IntrinsicsGenerator::AsyncFunctionAwaitCaught( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kAsyncFunctionAwaitCaught, arg_count); } TNode IntrinsicsGenerator::AsyncFunctionAwaitUncaught( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall( args, context, Builtin::kAsyncFunctionAwaitUncaught, arg_count); } TNode IntrinsicsGenerator::AsyncFunctionEnter( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kAsyncFunctionEnter, arg_count); } TNode IntrinsicsGenerator::AsyncFunctionReject( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kAsyncFunctionReject, arg_count); } TNode IntrinsicsGenerator::AsyncFunctionResolve( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kAsyncFunctionResolve, arg_count); } TNode IntrinsicsGenerator::AsyncGeneratorAwaitCaught( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kAsyncGeneratorAwaitCaught, arg_count); } TNode IntrinsicsGenerator::AsyncGeneratorAwaitUncaught( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall( args, context, Builtin::kAsyncGeneratorAwaitUncaught, arg_count); } TNode IntrinsicsGenerator::AsyncGeneratorReject( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kAsyncGeneratorReject, arg_count); } TNode IntrinsicsGenerator::AsyncGeneratorResolve( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kAsyncGeneratorResolve, arg_count); } TNode IntrinsicsGenerator::AsyncGeneratorYield( const InterpreterAssembler::RegListNodePair& args, TNode context, int arg_count) { return IntrinsicAsBuiltinCall(args, context, Builtin::kAsyncGeneratorYield, arg_count); } void IntrinsicsGenerator::AbortIfArgCountMismatch(int expected, TNode actual) { InterpreterAssembler::Label match(assembler_); TNode comparison = __ Word32Equal(actual, __ Int32Constant(expected)); __ GotoIf(comparison, &match); __ Abort(AbortReason::kWrongArgumentCountForInvokeIntrinsic); __ Goto(&match); __ BIND(&match); } #undef __ } // namespace interpreter } // namespace internal } // namespace v8