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