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/v8.h" 9 #include "test/cctest/cctest.h" 10 11 #include "src/compiler.h" 12 #include "src/compiler/pipeline.h" 13 #include "src/execution.h" 14 #include "src/full-codegen.h" 15 #include "src/handles.h" 16 #include "src/objects-inl.h" 17 #include "src/parser.h" 18 #include "src/rewriter.h" 19 #include "src/scopes.h" 20 21 #define USE_CRANKSHAFT 0 22 23 namespace v8 { 24 namespace internal { 25 namespace compiler { 26 27 class FunctionTester : public InitializedHandleScope { 28 public: 29 explicit FunctionTester(const char* source, uint32_t flags = 0) 30 : isolate(main_isolate()), 31 function((FLAG_allow_natives_syntax = true, NewFunction(source))), 32 flags_(flags) { 33 Compile(function); 34 const uint32_t supported_flags = CompilationInfo::kContextSpecializing | 35 CompilationInfo::kInliningEnabled | 36 CompilationInfo::kTypingEnabled; 37 CHECK_EQ(0, flags_ & ~supported_flags); 38 } 39 40 Isolate* isolate; 41 Handle<JSFunction> function; 42 43 Handle<JSFunction> Compile(Handle<JSFunction> function) { 44 #if V8_TURBOFAN_TARGET 45 CompilationInfoWithZone info(function); 46 47 CHECK(Parser::Parse(&info)); 48 info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); 49 if (flags_ & CompilationInfo::kContextSpecializing) { 50 info.MarkAsContextSpecializing(); 51 } 52 if (flags_ & CompilationInfo::kInliningEnabled) { 53 info.MarkAsInliningEnabled(); 54 } 55 if (flags_ & CompilationInfo::kTypingEnabled) { 56 info.MarkAsTypingEnabled(); 57 } 58 CHECK(Rewriter::Rewrite(&info)); 59 CHECK(Scope::Analyze(&info)); 60 CHECK(Compiler::EnsureDeoptimizationSupport(&info)); 61 62 Pipeline pipeline(&info); 63 Handle<Code> code = pipeline.GenerateCode(); 64 if (FLAG_turbo_deoptimization) { 65 info.context()->native_context()->AddOptimizedCode(*code); 66 } 67 68 CHECK(!code.is_null()); 69 function->ReplaceCode(*code); 70 #elif USE_CRANKSHAFT 71 Handle<Code> unoptimized = Handle<Code>(function->code()); 72 Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized, 73 Compiler::NOT_CONCURRENT); 74 CHECK(!code.is_null()); 75 #if ENABLE_DISASSEMBLER 76 if (FLAG_print_opt_code) { 77 CodeTracer::Scope tracing_scope(isolate->GetCodeTracer()); 78 code->Disassemble("test code", tracing_scope.file()); 79 } 80 #endif 81 function->ReplaceCode(*code); 82 #endif 83 return function; 84 } 85 86 MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) { 87 Handle<Object> args[] = {a, b}; 88 return Execution::Call(isolate, function, undefined(), 2, args, false); 89 } 90 91 void CheckThrows(Handle<Object> a, Handle<Object> b) { 92 TryCatch try_catch; 93 MaybeHandle<Object> no_result = Call(a, b); 94 CHECK(isolate->has_pending_exception()); 95 CHECK(try_catch.HasCaught()); 96 CHECK(no_result.is_null()); 97 // TODO(mstarzinger): Temporary workaround for issue chromium:362388. 98 isolate->OptionalRescheduleException(true); 99 } 100 101 v8::Handle<v8::Message> CheckThrowsReturnMessage(Handle<Object> a, 102 Handle<Object> b) { 103 TryCatch try_catch; 104 MaybeHandle<Object> no_result = Call(a, b); 105 CHECK(isolate->has_pending_exception()); 106 CHECK(try_catch.HasCaught()); 107 CHECK(no_result.is_null()); 108 // TODO(mstarzinger): Calling OptionalRescheduleException is a dirty hack, 109 // it's the only way to make Message() not to assert because an external 110 // exception has been caught by the try_catch. 111 isolate->OptionalRescheduleException(true); 112 return try_catch.Message(); 113 } 114 115 void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) { 116 Handle<Object> result = Call(a, b).ToHandleChecked(); 117 CHECK(expected->SameValue(*result)); 118 } 119 120 void CheckCall(Handle<Object> expected, Handle<Object> a) { 121 CheckCall(expected, a, undefined()); 122 } 123 124 void CheckCall(Handle<Object> expected) { 125 CheckCall(expected, undefined(), undefined()); 126 } 127 128 void CheckCall(double expected, double a, double b) { 129 CheckCall(Val(expected), Val(a), Val(b)); 130 } 131 132 void CheckTrue(Handle<Object> a, Handle<Object> b) { 133 CheckCall(true_value(), a, b); 134 } 135 136 void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); } 137 138 void CheckTrue(double a, double b) { 139 CheckCall(true_value(), Val(a), Val(b)); 140 } 141 142 void CheckFalse(Handle<Object> a, Handle<Object> b) { 143 CheckCall(false_value(), a, b); 144 } 145 146 void CheckFalse(Handle<Object> a) { 147 CheckCall(false_value(), a, undefined()); 148 } 149 150 void CheckFalse(double a, double b) { 151 CheckCall(false_value(), Val(a), Val(b)); 152 } 153 154 Handle<JSFunction> NewFunction(const char* source) { 155 return v8::Utils::OpenHandle( 156 *v8::Handle<v8::Function>::Cast(CompileRun(source))); 157 } 158 159 Handle<JSObject> NewObject(const char* source) { 160 return v8::Utils::OpenHandle( 161 *v8::Handle<v8::Object>::Cast(CompileRun(source))); 162 } 163 164 Handle<String> Val(const char* string) { 165 return isolate->factory()->InternalizeUtf8String(string); 166 } 167 168 Handle<Object> Val(double value) { 169 return isolate->factory()->NewNumber(value); 170 } 171 172 Handle<Object> infinity() { return isolate->factory()->infinity_value(); } 173 174 Handle<Object> minus_infinity() { return Val(-V8_INFINITY); } 175 176 Handle<Object> nan() { return isolate->factory()->nan_value(); } 177 178 Handle<Object> undefined() { return isolate->factory()->undefined_value(); } 179 180 Handle<Object> null() { return isolate->factory()->null_value(); } 181 182 Handle<Object> true_value() { return isolate->factory()->true_value(); } 183 184 Handle<Object> false_value() { return isolate->factory()->false_value(); } 185 186 private: 187 uint32_t flags_; 188 }; 189 } 190 } 191 } // namespace v8::internal::compiler 192 193 #endif // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_ 194