1// Copyright 2012 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#include "src/codegen.h"
6
7#if defined(V8_OS_AIX)
8#include <fenv.h>  // NOLINT(build/c++11)
9#endif
10#include "src/ast/prettyprinter.h"
11#include "src/bootstrapper.h"
12#include "src/compiler.h"
13#include "src/debug/debug.h"
14#include "src/parsing/parser.h"
15#include "src/runtime/runtime.h"
16
17namespace v8 {
18namespace internal {
19
20
21#if defined(V8_OS_WIN)
22double modulo(double x, double y) {
23  // Workaround MS fmod bugs. ECMA-262 says:
24  // dividend is finite and divisor is an infinity => result equals dividend
25  // dividend is a zero and divisor is nonzero finite => result equals dividend
26  if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) &&
27      !(x == 0 && (y != 0 && std::isfinite(y)))) {
28    x = fmod(x, y);
29  }
30  return x;
31}
32#else  // POSIX
33
34double modulo(double x, double y) {
35#if defined(V8_OS_AIX)
36  // AIX raises an underflow exception for (Number.MIN_VALUE % Number.MAX_VALUE)
37  feclearexcept(FE_ALL_EXCEPT);
38  double result = std::fmod(x, y);
39  int exception = fetestexcept(FE_UNDERFLOW);
40  return (exception ? x : result);
41#else
42  return std::fmod(x, y);
43#endif
44}
45#endif  // defined(V8_OS_WIN)
46
47
48#define UNARY_MATH_FUNCTION(name, generator)                             \
49  static UnaryMathFunctionWithIsolate fast_##name##_function = nullptr;  \
50  double std_##name(double x, Isolate* isolate) { return std::name(x); } \
51  void init_fast_##name##_function(Isolate* isolate) {                   \
52    if (FLAG_fast_math) fast_##name##_function = generator(isolate);     \
53    if (!fast_##name##_function) fast_##name##_function = std_##name;    \
54  }                                                                      \
55  void lazily_initialize_fast_##name(Isolate* isolate) {                 \
56    if (!fast_##name##_function) init_fast_##name##_function(isolate);   \
57  }                                                                      \
58  double fast_##name(double x, Isolate* isolate) {                       \
59    return (*fast_##name##_function)(x, isolate);                        \
60  }
61
62UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction)
63
64#undef UNARY_MATH_FUNCTION
65
66
67#define __ ACCESS_MASM(masm_)
68
69#ifdef DEBUG
70
71Comment::Comment(MacroAssembler* masm, const char* msg)
72    : masm_(masm), msg_(msg) {
73  __ RecordComment(msg);
74}
75
76
77Comment::~Comment() {
78  if (msg_[0] == '[') __ RecordComment("]");
79}
80
81#endif  // DEBUG
82
83#undef __
84
85
86void CodeGenerator::MakeCodePrologue(CompilationInfo* info, const char* kind) {
87  bool print_source = false;
88  bool print_ast = false;
89  const char* ftype;
90
91  if (info->isolate()->bootstrapper()->IsActive()) {
92    print_source = FLAG_print_builtin_source;
93    print_ast = FLAG_print_builtin_ast;
94    ftype = "builtin";
95  } else {
96    print_source = FLAG_print_source;
97    print_ast = FLAG_print_ast;
98    ftype = "user-defined";
99  }
100
101  if (FLAG_trace_codegen || print_source || print_ast) {
102    base::SmartArrayPointer<char> name = info->GetDebugName();
103    PrintF("[generating %s code for %s function: %s]\n", kind, ftype,
104           name.get());
105  }
106
107#ifdef DEBUG
108  if (info->parse_info() && print_source) {
109    PrintF("--- Source from AST ---\n%s\n",
110           PrettyPrinter(info->isolate()).PrintProgram(info->literal()));
111  }
112
113  if (info->parse_info() && print_ast) {
114    PrintF("--- AST ---\n%s\n",
115           AstPrinter(info->isolate()).PrintProgram(info->literal()));
116  }
117#endif  // DEBUG
118}
119
120
121Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
122                                             CompilationInfo* info) {
123  Isolate* isolate = info->isolate();
124
125  // Allocate and install the code.
126  CodeDesc desc;
127  Code::Flags flags = info->code_flags();
128  bool is_crankshafted =
129      Code::ExtractKindFromFlags(flags) == Code::OPTIMIZED_FUNCTION ||
130      info->IsStub();
131  masm->GetCode(&desc);
132  Handle<Code> code =
133      isolate->factory()->NewCode(desc, flags, masm->CodeObject(),
134                                  false, is_crankshafted,
135                                  info->prologue_offset(),
136                                  info->is_debug() && !is_crankshafted);
137  isolate->counters()->total_compiled_code_size()->Increment(
138      code->instruction_size());
139  isolate->heap()->IncrementCodeGeneratedBytes(is_crankshafted,
140      code->instruction_size());
141  return code;
142}
143
144
145void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
146#ifdef ENABLE_DISASSEMBLER
147  AllowDeferredHandleDereference allow_deference_for_print_code;
148  Isolate* isolate = info->isolate();
149  bool print_code =
150      isolate->bootstrapper()->IsActive()
151          ? FLAG_print_builtin_code
152          : (FLAG_print_code || (info->IsStub() && FLAG_print_code_stubs) ||
153             (info->IsOptimizing() && FLAG_print_opt_code));
154  if (print_code) {
155    base::SmartArrayPointer<char> debug_name = info->GetDebugName();
156    CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
157    OFStream os(tracing_scope.file());
158
159    // Print the source code if available.
160    bool print_source =
161        info->parse_info() && (code->kind() == Code::OPTIMIZED_FUNCTION ||
162                               code->kind() == Code::FUNCTION);
163    if (print_source) {
164      Handle<SharedFunctionInfo> shared = info->shared_info();
165      Handle<Script> script = info->script();
166      if (!script->IsUndefined(isolate) &&
167          !script->source()->IsUndefined(isolate)) {
168        os << "--- Raw source ---\n";
169        StringCharacterStream stream(String::cast(script->source()),
170                                     shared->start_position());
171        // fun->end_position() points to the last character in the stream. We
172        // need to compensate by adding one to calculate the length.
173        int source_len = shared->end_position() - shared->start_position() + 1;
174        for (int i = 0; i < source_len; i++) {
175          if (stream.HasMore()) {
176            os << AsReversiblyEscapedUC16(stream.GetNext());
177          }
178        }
179        os << "\n\n";
180      }
181    }
182    if (info->IsOptimizing()) {
183      if (FLAG_print_unopt_code && info->parse_info()) {
184        os << "--- Unoptimized code ---\n";
185        info->closure()->shared()->code()->Disassemble(debug_name.get(), os);
186      }
187      os << "--- Optimized code ---\n"
188         << "optimization_id = " << info->optimization_id() << "\n";
189    } else {
190      os << "--- Code ---\n";
191    }
192    if (print_source) {
193      Handle<SharedFunctionInfo> shared = info->shared_info();
194      os << "source_position = " << shared->start_position() << "\n";
195    }
196    code->Disassemble(debug_name.get(), os);
197    os << "--- End code ---\n";
198  }
199#endif  // ENABLE_DISASSEMBLER
200}
201
202}  // namespace internal
203}  // namespace v8
204