function-tester.cc 5.97 KB
Newer Older
1 2 3 4 5 6
// Copyright 2014 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 "test/cctest/compiler/function-tester.h"

7
#include "src/api-inl.h"
8 9 10 11 12 13
#include "src/compiler.h"
#include "src/compiler/linkage.h"
#include "src/compiler/pipeline.h"
#include "src/execution.h"
#include "src/handles.h"
#include "src/objects-inl.h"
14
#include "src/optimized-compilation-info.h"
15 16 17 18 19 20 21 22 23
#include "src/parsing/parse-info.h"
#include "test/cctest/cctest.h"

namespace v8 {
namespace internal {
namespace compiler {

FunctionTester::FunctionTester(const char* source, uint32_t flags)
    : isolate(main_isolate()),
24
      canonical(isolate),
25 26 27
      function((FLAG_allow_natives_syntax = true, NewFunction(source))),
      flags_(flags) {
  Compile(function);
28
  const uint32_t supported_flags = OptimizedCompilationInfo::kInliningEnabled;
29 30 31 32 33
  CHECK_EQ(0u, flags_ & ~supported_flags);
}

FunctionTester::FunctionTester(Graph* graph, int param_count)
    : isolate(main_isolate()),
34
      canonical(isolate),
35 36 37 38 39 40 41
      function(NewFunction(BuildFunction(param_count).c_str())),
      flags_(0) {
  CompileGraph(graph);
}

FunctionTester::FunctionTester(Handle<Code> code, int param_count)
    : isolate(main_isolate()),
42
      canonical(isolate),
43 44 45
      function((FLAG_allow_natives_syntax = true,
                NewFunction(BuildFunction(param_count).c_str()))),
      flags_(0) {
46
  CHECK(!code.is_null());
47
  Compile(function);
48
  function->set_code(*code);
49 50
}

51
FunctionTester::FunctionTester(Handle<Code> code) : FunctionTester(code, 0) {}
52

53 54 55 56 57 58 59 60 61
void FunctionTester::CheckThrows(Handle<Object> a) {
  TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
  MaybeHandle<Object> no_result = Call(a);
  CHECK(isolate->has_pending_exception());
  CHECK(try_catch.HasCaught());
  CHECK(no_result.is_null());
  isolate->OptionalRescheduleException(true);
}

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
void FunctionTester::CheckThrows(Handle<Object> a, Handle<Object> b) {
  TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
  MaybeHandle<Object> no_result = Call(a, b);
  CHECK(isolate->has_pending_exception());
  CHECK(try_catch.HasCaught());
  CHECK(no_result.is_null());
  isolate->OptionalRescheduleException(true);
}

v8::Local<v8::Message> FunctionTester::CheckThrowsReturnMessage(
    Handle<Object> a, Handle<Object> b) {
  TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
  MaybeHandle<Object> no_result = Call(a, b);
  CHECK(isolate->has_pending_exception());
  CHECK(try_catch.HasCaught());
  CHECK(no_result.is_null());
  isolate->OptionalRescheduleException(true);
  CHECK(!try_catch.Message().IsEmpty());
  return try_catch.Message();
}

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
void FunctionTester::CheckCall(Handle<Object> expected, Handle<Object> a,
                               Handle<Object> b, Handle<Object> c,
                               Handle<Object> d) {
  Handle<Object> result = Call(a, b, c, d).ToHandleChecked();
  CHECK(expected->SameValue(*result));
}

Handle<JSFunction> FunctionTester::NewFunction(const char* source) {
  return Handle<JSFunction>::cast(v8::Utils::OpenHandle(
      *v8::Local<v8::Function>::Cast(CompileRun(source))));
}

Handle<JSObject> FunctionTester::NewObject(const char* source) {
  return Handle<JSObject>::cast(
      v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(CompileRun(source))));
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
Handle<String> FunctionTester::Val(const char* string) {
  return isolate->factory()->InternalizeUtf8String(string);
}

Handle<Object> FunctionTester::Val(double value) {
  return isolate->factory()->NewNumber(value);
}

Handle<Object> FunctionTester::infinity() {
  return isolate->factory()->infinity_value();
}

Handle<Object> FunctionTester::minus_infinity() { return Val(-V8_INFINITY); }

Handle<Object> FunctionTester::nan() { return isolate->factory()->nan_value(); }

Handle<Object> FunctionTester::undefined() {
  return isolate->factory()->undefined_value();
}

Handle<Object> FunctionTester::null() {
  return isolate->factory()->null_value();
}

Handle<Object> FunctionTester::true_value() {
  return isolate->factory()->true_value();
}

Handle<Object> FunctionTester::false_value() {
  return isolate->factory()->false_value();
}

132 133
Handle<JSFunction> FunctionTester::ForMachineGraph(Graph* graph,
                                                   int param_count) {
134
  JSFunction* p = nullptr;
135 136 137 138
  {  // because of the implicit handle scope of FunctionTester.
    FunctionTester f(graph, param_count);
    p = *f.function;
  }
139 140
  return Handle<JSFunction>(
      p, p->GetIsolate());  // allocated in outer handle scope.
141 142
}

143
Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> function) {
144
  Handle<SharedFunctionInfo> shared(function->shared(), isolate);
145 146
  Zone zone(isolate->allocator(), ZONE_NAME);
  OptimizedCompilationInfo info(&zone, isolate, shared, function);
147

148
  if (flags_ & OptimizedCompilationInfo::kInliningEnabled) {
149 150
    info.MarkAsInliningEnabled();
  }
151

152 153
  CHECK(function->is_compiled() ||
        Compiler::Compile(function, Compiler::CLEAR_EXCEPTION));
154
  CHECK(info.shared_info()->HasBytecodeArray());
155
  JSFunction::EnsureFeedbackVector(function);
156

157 158
  Handle<Code> code =
      Pipeline::GenerateCodeForTesting(&info, isolate).ToHandleChecked();
159
  info.context()->native_context()->AddOptimizedCode(*code);
160
  function->set_code(*code);
161 162 163 164 165 166
  return function;
}

// Compile the given machine graph instead of the source of the function
// and replace the JSFunction's code with the result.
Handle<JSFunction> FunctionTester::CompileGraph(Graph* graph) {
167
  Handle<SharedFunctionInfo> shared(function->shared(), isolate);
168 169
  Zone zone(isolate->allocator(), ZONE_NAME);
  OptimizedCompilationInfo info(&zone, isolate, shared, function);
170

171
  auto call_descriptor = Linkage::ComputeIncoming(&zone, &info);
172
  Handle<Code> code =
173 174
      Pipeline::GenerateCodeForTesting(&info, isolate, call_descriptor, graph,
                                       AssemblerOptions::Default(isolate))
175
          .ToHandleChecked();
176
  function->set_code(*code);
177 178 179 180 181 182
  return function;
}

}  // namespace compiler
}  // namespace internal
}  // namespace v8