|  | // 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. | 
|  |  | 
|  | #ifndef V8_TEST_CCTEST_INTERPRETER_INTERPRETER_TESTER_H_ | 
|  | #define V8_TEST_CCTEST_INTERPRETER_INTERPRETER_TESTER_H_ | 
|  |  | 
|  | #include "src/init/v8.h" | 
|  |  | 
|  | #include "src/api/api.h" | 
|  | #include "src/execution/execution.h" | 
|  | #include "src/handles/handles.h" | 
|  | #include "src/interpreter/bytecode-array-builder.h" | 
|  | #include "src/interpreter/interpreter.h" | 
|  | #include "src/objects/feedback-cell.h" | 
|  | #include "test/cctest/cctest.h" | 
|  | #include "test/cctest/test-feedback-vector.h" | 
|  |  | 
|  | namespace v8 { | 
|  | namespace internal { | 
|  | namespace interpreter { | 
|  |  | 
|  | template <class... A> | 
|  | static MaybeHandle<Object> CallInterpreter(Isolate* isolate, | 
|  | Handle<JSFunction> function, | 
|  | Handle<Object> receiver, A... args) { | 
|  | // Pad the array with an empty handle to ensure that argv size is at least 1. | 
|  | // It avoids MSVC error C2466. | 
|  | Handle<Object> argv[] = {args..., Handle<Object>()}; | 
|  | return Execution::Call(isolate, function, receiver, sizeof...(args), argv); | 
|  | } | 
|  |  | 
|  | template <class... A> | 
|  | class InterpreterCallable { | 
|  | public: | 
|  | virtual ~InterpreterCallable() = default; | 
|  |  | 
|  | FeedbackVector vector() const { return function_->feedback_vector(); } | 
|  |  | 
|  | protected: | 
|  | InterpreterCallable(Isolate* isolate, Handle<JSFunction> function) | 
|  | : isolate_(isolate), function_(function) {} | 
|  |  | 
|  | Isolate* isolate_; | 
|  | Handle<JSFunction> function_; | 
|  | }; | 
|  |  | 
|  | template <class... A> | 
|  | class InterpreterCallableUndefinedReceiver : public InterpreterCallable<A...> { | 
|  | public: | 
|  | InterpreterCallableUndefinedReceiver(Isolate* isolate, | 
|  | Handle<JSFunction> function) | 
|  | : InterpreterCallable<A...>(isolate, function) {} | 
|  |  | 
|  | MaybeHandle<Object> operator()(A... args) { | 
|  | return CallInterpreter(this->isolate_, this->function_, | 
|  | this->isolate_->factory()->undefined_value(), | 
|  | args...); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <class... A> | 
|  | class InterpreterCallableWithReceiver : public InterpreterCallable<A...> { | 
|  | public: | 
|  | InterpreterCallableWithReceiver(Isolate* isolate, Handle<JSFunction> function) | 
|  | : InterpreterCallable<A...>(isolate, function) {} | 
|  |  | 
|  | MaybeHandle<Object> operator()(Handle<Object> receiver, A... args) { | 
|  | return CallInterpreter(this->isolate_, this->function_, receiver, args...); | 
|  | } | 
|  | }; | 
|  |  | 
|  | class InterpreterTester { | 
|  | public: | 
|  | InterpreterTester(Isolate* isolate, const char* source, | 
|  | MaybeHandle<BytecodeArray> bytecode, | 
|  | MaybeHandle<FeedbackMetadata> feedback_metadata, | 
|  | const char* filter); | 
|  |  | 
|  | InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode, | 
|  | MaybeHandle<FeedbackMetadata> feedback_metadata = | 
|  | MaybeHandle<FeedbackMetadata>(), | 
|  | const char* filter = kFunctionName); | 
|  |  | 
|  | InterpreterTester(Isolate* isolate, const char* source, | 
|  | const char* filter = kFunctionName); | 
|  |  | 
|  | virtual ~InterpreterTester(); | 
|  | InterpreterTester(const InterpreterTester&) = delete; | 
|  | InterpreterTester& operator=(const InterpreterTester&) = delete; | 
|  |  | 
|  | template <class... A> | 
|  | InterpreterCallableUndefinedReceiver<A...> GetCallable() { | 
|  | return InterpreterCallableUndefinedReceiver<A...>( | 
|  | isolate_, GetBytecodeFunction<A...>()); | 
|  | } | 
|  |  | 
|  | template <class... A> | 
|  | InterpreterCallableWithReceiver<A...> GetCallableWithReceiver() { | 
|  | return InterpreterCallableWithReceiver<A...>(isolate_, | 
|  | GetBytecodeFunction<A...>()); | 
|  | } | 
|  |  | 
|  | Local<Message> CheckThrowsReturnMessage(); | 
|  |  | 
|  | static Handle<Object> NewObject(const char* script); | 
|  |  | 
|  | static Handle<String> GetName(Isolate* isolate, const char* name); | 
|  |  | 
|  | static std::string SourceForBody(const char* body); | 
|  |  | 
|  | static std::string function_name(); | 
|  |  | 
|  | static const char kFunctionName[]; | 
|  |  | 
|  | // Expose raw RegisterList construction to tests. | 
|  | static RegisterList NewRegisterList(int first_reg_index, int register_count) { | 
|  | return RegisterList(first_reg_index, register_count); | 
|  | } | 
|  |  | 
|  | inline bool HasFeedbackMetadata() { return !feedback_metadata_.is_null(); } | 
|  |  | 
|  | private: | 
|  | Isolate* isolate_; | 
|  | const char* source_; | 
|  | MaybeHandle<BytecodeArray> bytecode_; | 
|  | MaybeHandle<FeedbackMetadata> feedback_metadata_; | 
|  |  | 
|  | template <class... A> | 
|  | Handle<JSFunction> GetBytecodeFunction() { | 
|  | Handle<JSFunction> function; | 
|  | IsCompiledScope is_compiled_scope; | 
|  | if (source_) { | 
|  | CompileRun(source_); | 
|  | v8::Local<v8::Context> context = | 
|  | v8::Isolate::GetCurrent()->GetCurrentContext(); | 
|  | Local<Function> api_function = | 
|  | Local<Function>::Cast(CcTest::global() | 
|  | ->Get(context, v8_str(kFunctionName)) | 
|  | .ToLocalChecked()); | 
|  | function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function)); | 
|  | is_compiled_scope = function->shared().is_compiled_scope(isolate_); | 
|  | } else { | 
|  | int arg_count = sizeof...(A); | 
|  | std::string source("(function " + function_name() + "("); | 
|  | for (int i = 0; i < arg_count; i++) { | 
|  | source += i == 0 ? "a" : ", a"; | 
|  | } | 
|  | source += "){})"; | 
|  | function = Handle<JSFunction>::cast(v8::Utils::OpenHandle( | 
|  | *v8::Local<v8::Function>::Cast(CompileRun(source.c_str())))); | 
|  | function->set_code(*BUILTIN_CODE(isolate_, InterpreterEntryTrampoline)); | 
|  | is_compiled_scope = function->shared().is_compiled_scope(isolate_); | 
|  | } | 
|  |  | 
|  | if (!bytecode_.is_null()) { | 
|  | function->shared().set_function_data(*bytecode_.ToHandleChecked(), | 
|  | kReleaseStore); | 
|  | is_compiled_scope = function->shared().is_compiled_scope(isolate_); | 
|  | } | 
|  | if (HasFeedbackMetadata()) { | 
|  | function->set_raw_feedback_cell(isolate_->heap()->many_closures_cell()); | 
|  | // Set the raw feedback metadata to circumvent checks that we are not | 
|  | // overwriting existing metadata. | 
|  | function->shared().set_raw_outer_scope_info_or_feedback_metadata( | 
|  | *feedback_metadata_.ToHandleChecked()); | 
|  | JSFunction::EnsureFeedbackVector(function, &is_compiled_scope); | 
|  | } | 
|  | return function; | 
|  | } | 
|  | }; | 
|  |  | 
|  | }  // namespace interpreter | 
|  | }  // namespace internal | 
|  | }  // namespace v8 | 
|  |  | 
|  | #endif  // V8_TEST_CCTEST_INTERPRETER_INTERPRETER_TESTER_H_ |