Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1 | // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef V8_CCTEST_COMPILER_FUNCTION_TESTER_H_ |
| 6 | #define V8_CCTEST_COMPILER_FUNCTION_TESTER_H_ |
| 7 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 8 | #include "src/ast/ast-numbering.h" |
| 9 | #include "src/ast/scopes.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 10 | #include "src/compiler.h" |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 11 | #include "src/compiler/linkage.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 12 | #include "src/compiler/pipeline.h" |
| 13 | #include "src/execution.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 14 | #include "src/full-codegen/full-codegen.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 15 | #include "src/handles.h" |
| 16 | #include "src/objects-inl.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 17 | #include "src/parsing/parser.h" |
| 18 | #include "src/parsing/rewriter.h" |
| 19 | #include "test/cctest/cctest.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 20 | |
| 21 | namespace v8 { |
| 22 | namespace internal { |
| 23 | namespace compiler { |
| 24 | |
| 25 | class FunctionTester : public InitializedHandleScope { |
| 26 | public: |
| 27 | explicit FunctionTester(const char* source, uint32_t flags = 0) |
| 28 | : isolate(main_isolate()), |
| 29 | function((FLAG_allow_natives_syntax = true, NewFunction(source))), |
| 30 | flags_(flags) { |
| 31 | Compile(function); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 32 | const uint32_t supported_flags = |
| 33 | CompilationInfo::kFunctionContextSpecializing | |
| 34 | CompilationInfo::kInliningEnabled | CompilationInfo::kTypingEnabled; |
| 35 | CHECK_EQ(0u, flags_ & ~supported_flags); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 36 | } |
| 37 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 38 | FunctionTester(Graph* graph, int param_count) |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 39 | : isolate(main_isolate()), |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 40 | function(NewFunction(BuildFunction(param_count).c_str())), |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 41 | flags_(0) { |
| 42 | CompileGraph(graph); |
| 43 | } |
| 44 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 45 | FunctionTester(const CallInterfaceDescriptor& descriptor, Handle<Code> code) |
| 46 | : isolate(main_isolate()), |
| 47 | function( |
| 48 | (FLAG_allow_natives_syntax = true, |
| 49 | NewFunction(BuildFunctionFromDescriptor(descriptor).c_str()))), |
| 50 | flags_(0) { |
| 51 | Compile(function); |
| 52 | function->ReplaceCode(*code); |
| 53 | } |
| 54 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 55 | Isolate* isolate; |
| 56 | Handle<JSFunction> function; |
| 57 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 58 | MaybeHandle<Object> Call() { |
| 59 | return Execution::Call(isolate, function, undefined(), 0, nullptr); |
| 60 | } |
| 61 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 62 | MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) { |
| 63 | Handle<Object> args[] = {a, b}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 64 | return Execution::Call(isolate, function, undefined(), 2, args); |
| 65 | } |
| 66 | |
| 67 | MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b, Handle<Object> c, |
| 68 | Handle<Object> d) { |
| 69 | Handle<Object> args[] = {a, b, c, d}; |
| 70 | return Execution::Call(isolate, function, undefined(), 4, args); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | void CheckThrows(Handle<Object> a, Handle<Object> b) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 74 | TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 75 | MaybeHandle<Object> no_result = Call(a, b); |
| 76 | CHECK(isolate->has_pending_exception()); |
| 77 | CHECK(try_catch.HasCaught()); |
| 78 | CHECK(no_result.is_null()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 79 | isolate->OptionalRescheduleException(true); |
| 80 | } |
| 81 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 82 | v8::Local<v8::Message> CheckThrowsReturnMessage(Handle<Object> a, |
| 83 | Handle<Object> b) { |
| 84 | TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 85 | MaybeHandle<Object> no_result = Call(a, b); |
| 86 | CHECK(isolate->has_pending_exception()); |
| 87 | CHECK(try_catch.HasCaught()); |
| 88 | CHECK(no_result.is_null()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 89 | isolate->OptionalRescheduleException(true); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 90 | CHECK(!try_catch.Message().IsEmpty()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 91 | return try_catch.Message(); |
| 92 | } |
| 93 | |
| 94 | void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) { |
| 95 | Handle<Object> result = Call(a, b).ToHandleChecked(); |
| 96 | CHECK(expected->SameValue(*result)); |
| 97 | } |
| 98 | |
| 99 | void CheckCall(Handle<Object> expected, Handle<Object> a) { |
| 100 | CheckCall(expected, a, undefined()); |
| 101 | } |
| 102 | |
| 103 | void CheckCall(Handle<Object> expected) { |
| 104 | CheckCall(expected, undefined(), undefined()); |
| 105 | } |
| 106 | |
| 107 | void CheckCall(double expected, double a, double b) { |
| 108 | CheckCall(Val(expected), Val(a), Val(b)); |
| 109 | } |
| 110 | |
| 111 | void CheckTrue(Handle<Object> a, Handle<Object> b) { |
| 112 | CheckCall(true_value(), a, b); |
| 113 | } |
| 114 | |
| 115 | void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); } |
| 116 | |
| 117 | void CheckTrue(double a, double b) { |
| 118 | CheckCall(true_value(), Val(a), Val(b)); |
| 119 | } |
| 120 | |
| 121 | void CheckFalse(Handle<Object> a, Handle<Object> b) { |
| 122 | CheckCall(false_value(), a, b); |
| 123 | } |
| 124 | |
| 125 | void CheckFalse(Handle<Object> a) { |
| 126 | CheckCall(false_value(), a, undefined()); |
| 127 | } |
| 128 | |
| 129 | void CheckFalse(double a, double b) { |
| 130 | CheckCall(false_value(), Val(a), Val(b)); |
| 131 | } |
| 132 | |
| 133 | Handle<JSFunction> NewFunction(const char* source) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 134 | return Handle<JSFunction>::cast(v8::Utils::OpenHandle( |
| 135 | *v8::Local<v8::Function>::Cast(CompileRun(source)))); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 136 | } |
| 137 | |
| 138 | Handle<JSObject> NewObject(const char* source) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 139 | return Handle<JSObject>::cast(v8::Utils::OpenHandle( |
| 140 | *v8::Local<v8::Object>::Cast(CompileRun(source)))); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | Handle<String> Val(const char* string) { |
| 144 | return isolate->factory()->InternalizeUtf8String(string); |
| 145 | } |
| 146 | |
| 147 | Handle<Object> Val(double value) { |
| 148 | return isolate->factory()->NewNumber(value); |
| 149 | } |
| 150 | |
| 151 | Handle<Object> infinity() { return isolate->factory()->infinity_value(); } |
| 152 | |
| 153 | Handle<Object> minus_infinity() { return Val(-V8_INFINITY); } |
| 154 | |
| 155 | Handle<Object> nan() { return isolate->factory()->nan_value(); } |
| 156 | |
| 157 | Handle<Object> undefined() { return isolate->factory()->undefined_value(); } |
| 158 | |
| 159 | Handle<Object> null() { return isolate->factory()->null_value(); } |
| 160 | |
| 161 | Handle<Object> true_value() { return isolate->factory()->true_value(); } |
| 162 | |
| 163 | Handle<Object> false_value() { return isolate->factory()->false_value(); } |
| 164 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 165 | Handle<JSFunction> Compile(Handle<JSFunction> function) { |
| 166 | // TODO(titzer): make this method private. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 167 | Zone zone; |
| 168 | ParseInfo parse_info(&zone, function); |
| 169 | CompilationInfo info(&parse_info); |
| 170 | info.MarkAsDeoptimizationEnabled(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 171 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 172 | CHECK(Parser::ParseStatic(info.parse_info())); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 173 | info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 174 | if (flags_ & CompilationInfo::kFunctionContextSpecializing) { |
| 175 | info.MarkAsFunctionContextSpecializing(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 176 | } |
| 177 | if (flags_ & CompilationInfo::kInliningEnabled) { |
| 178 | info.MarkAsInliningEnabled(); |
| 179 | } |
| 180 | if (flags_ & CompilationInfo::kTypingEnabled) { |
| 181 | info.MarkAsTypingEnabled(); |
| 182 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 183 | CHECK(Compiler::Analyze(info.parse_info())); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 184 | CHECK(Compiler::EnsureDeoptimizationSupport(&info)); |
| 185 | |
| 186 | Pipeline pipeline(&info); |
| 187 | Handle<Code> code = pipeline.GenerateCode(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 188 | CHECK(!code.is_null()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 189 | info.dependencies()->Commit(code); |
| 190 | info.context()->native_context()->AddOptimizedCode(*code); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 191 | function->ReplaceCode(*code); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 192 | return function; |
| 193 | } |
| 194 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 195 | static Handle<JSFunction> ForMachineGraph(Graph* graph, int param_count) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 196 | JSFunction* p = NULL; |
| 197 | { // because of the implicit handle scope of FunctionTester. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 198 | FunctionTester f(graph, param_count); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 199 | p = *f.function; |
| 200 | } |
| 201 | return Handle<JSFunction>(p); // allocated in outer handle scope. |
| 202 | } |
| 203 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 204 | private: |
| 205 | uint32_t flags_; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 206 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 207 | std::string BuildFunction(int param_count) { |
| 208 | std::string function_string = "(function("; |
| 209 | if (param_count > 0) { |
| 210 | char next = 'a'; |
| 211 | function_string += next; |
| 212 | while (param_count-- > 0) { |
| 213 | function_string += ','; |
| 214 | function_string += ++next; |
| 215 | } |
| 216 | } |
| 217 | function_string += "){})"; |
| 218 | return function_string; |
| 219 | } |
| 220 | |
| 221 | std::string BuildFunctionFromDescriptor( |
| 222 | const CallInterfaceDescriptor& descriptor) { |
| 223 | return BuildFunction(descriptor.GetParameterCount()); |
| 224 | } |
| 225 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 226 | // Compile the given machine graph instead of the source of the function |
| 227 | // and replace the JSFunction's code with the result. |
| 228 | Handle<JSFunction> CompileGraph(Graph* graph) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 229 | Zone zone; |
| 230 | ParseInfo parse_info(&zone, function); |
| 231 | CompilationInfo info(&parse_info); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 232 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 233 | CHECK(Parser::ParseStatic(info.parse_info())); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 234 | info.SetOptimizing(BailoutId::None(), |
| 235 | Handle<Code>(function->shared()->code())); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 236 | CHECK(Compiler::Analyze(info.parse_info())); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 237 | CHECK(Compiler::EnsureDeoptimizationSupport(&info)); |
| 238 | |
| 239 | Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph); |
| 240 | CHECK(!code.is_null()); |
| 241 | function->ReplaceCode(*code); |
| 242 | return function; |
| 243 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 244 | }; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 245 | } // namespace compiler |
| 246 | } // namespace internal |
| 247 | } // namespace v8 |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 248 | |
| 249 | #endif // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_ |