blob: 8822eddb4b8bbb793459e18a9296445b40884e00 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "bootstrapper.h"
31#include "codegen-inl.h"
Steve Blockd0582a62009-12-15 09:54:21 +000032#include "compiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "debug.h"
34#include "oprofile-agent.h"
35#include "prettyprinter.h"
36#include "register-allocator-inl.h"
37#include "rewriter.h"
38#include "runtime.h"
39#include "scopeinfo.h"
40#include "stub-cache.h"
41
42namespace v8 {
43namespace internal {
44
45
46CodeGenerator* CodeGeneratorScope::top_ = NULL;
47
48
49DeferredCode::DeferredCode()
50 : masm_(CodeGeneratorScope::Current()->masm()),
51 statement_position_(masm_->current_statement_position()),
52 position_(masm_->current_position()) {
53 ASSERT(statement_position_ != RelocInfo::kNoPosition);
54 ASSERT(position_ != RelocInfo::kNoPosition);
55
56 CodeGeneratorScope::Current()->AddDeferred(this);
57#ifdef DEBUG
58 comment_ = "";
59#endif
60
61 // Copy the register locations from the code generator's frame.
62 // These are the registers that will be spilled on entry to the
63 // deferred code and restored on exit.
64 VirtualFrame* frame = CodeGeneratorScope::Current()->frame();
65 int sp_offset = frame->fp_relative(frame->stack_pointer_);
66 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
67 int loc = frame->register_location(i);
68 if (loc == VirtualFrame::kIllegalIndex) {
69 registers_[i] = kIgnore;
70 } else if (frame->elements_[loc].is_synced()) {
71 // Needs to be restored on exit but not saved on entry.
72 registers_[i] = frame->fp_relative(loc) | kSyncedFlag;
73 } else {
74 int offset = frame->fp_relative(loc);
75 registers_[i] = (offset < sp_offset) ? kPush : offset;
76 }
77 }
78}
79
80
81void CodeGenerator::ProcessDeferred() {
82 while (!deferred_.is_empty()) {
83 DeferredCode* code = deferred_.RemoveLast();
84 ASSERT(masm_ == code->masm());
85 // Record position of deferred code stub.
86 masm_->RecordStatementPosition(code->statement_position());
87 if (code->position() != RelocInfo::kNoPosition) {
88 masm_->RecordPosition(code->position());
89 }
90 // Generate the code.
91 Comment cmnt(masm_, code->comment());
92 masm_->bind(code->entry_label());
93 code->SaveRegisters();
94 code->Generate();
95 code->RestoreRegisters();
96 masm_->jmp(code->exit_label());
97 }
98}
99
100
101void CodeGenerator::SetFrame(VirtualFrame* new_frame,
102 RegisterFile* non_frame_registers) {
103 RegisterFile saved_counts;
104 if (has_valid_frame()) {
105 frame_->DetachFromCodeGenerator();
106 // The remaining register reference counts are the non-frame ones.
107 allocator_->SaveTo(&saved_counts);
108 }
109
110 if (new_frame != NULL) {
111 // Restore the non-frame register references that go with the new frame.
112 allocator_->RestoreFrom(non_frame_registers);
113 new_frame->AttachToCodeGenerator();
114 }
115
116 frame_ = new_frame;
117 saved_counts.CopyTo(non_frame_registers);
118}
119
120
121void CodeGenerator::DeleteFrame() {
122 if (has_valid_frame()) {
123 frame_->DetachFromCodeGenerator();
124 frame_ = NULL;
125 }
126}
127
128
Steve Block3ce2e202009-11-05 08:53:23 +0000129void CodeGenerator::MakeCodePrologue(FunctionLiteral* fun) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000130#ifdef DEBUG
131 bool print_source = false;
132 bool print_ast = false;
Steve Block3ce2e202009-11-05 08:53:23 +0000133 bool print_json_ast = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000134 const char* ftype;
135
136 if (Bootstrapper::IsActive()) {
137 print_source = FLAG_print_builtin_source;
138 print_ast = FLAG_print_builtin_ast;
Steve Block3ce2e202009-11-05 08:53:23 +0000139 print_json_ast = FLAG_print_builtin_json_ast;
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 ftype = "builtin";
141 } else {
142 print_source = FLAG_print_source;
143 print_ast = FLAG_print_ast;
Steve Block3ce2e202009-11-05 08:53:23 +0000144 print_json_ast = FLAG_print_json_ast;
Steve Blocka7e24c12009-10-30 11:49:00 +0000145 ftype = "user-defined";
146 }
147
148 if (FLAG_trace_codegen || print_source || print_ast) {
149 PrintF("*** Generate code for %s function: ", ftype);
Steve Block3ce2e202009-11-05 08:53:23 +0000150 fun->name()->ShortPrint();
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 PrintF(" ***\n");
152 }
153
154 if (print_source) {
Steve Block3ce2e202009-11-05 08:53:23 +0000155 PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(fun));
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 }
157
158 if (print_ast) {
Steve Block3ce2e202009-11-05 08:53:23 +0000159 PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(fun));
160 }
161
162 if (print_json_ast) {
163 JsonAstBuilder builder;
164 PrintF("%s", builder.BuildProgram(fun));
Steve Blocka7e24c12009-10-30 11:49:00 +0000165 }
166#endif // DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000167}
Steve Blocka7e24c12009-10-30 11:49:00 +0000168
Steve Blocka7e24c12009-10-30 11:49:00 +0000169
Steve Block3ce2e202009-11-05 08:53:23 +0000170Handle<Code> CodeGenerator::MakeCodeEpilogue(FunctionLiteral* fun,
171 MacroAssembler* masm,
172 Code::Flags flags,
173 Handle<Script> script) {
174 // Allocate and install the code.
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 CodeDesc desc;
Steve Block3ce2e202009-11-05 08:53:23 +0000176 masm->GetCode(&desc);
177 ZoneScopeInfo sinfo(fun->scope());
178 Handle<Code> code =
179 Factory::NewCode(desc, &sinfo, flags, masm->CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000180
181 // Add unresolved entries in the code to the fixup list.
Steve Block3ce2e202009-11-05 08:53:23 +0000182 Bootstrapper::AddFixup(*code, masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000183
184#ifdef ENABLE_DISASSEMBLER
Steve Block3ce2e202009-11-05 08:53:23 +0000185 bool print_code = Bootstrapper::IsActive()
186 ? FLAG_print_builtin_code
187 : FLAG_print_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000188 if (print_code) {
189 // Print the source code if available.
190 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
191 PrintF("--- Raw source ---\n");
192 StringInputBuffer stream(String::cast(script->source()));
Steve Block3ce2e202009-11-05 08:53:23 +0000193 stream.Seek(fun->start_position());
194 // fun->end_position() points to the last character in the stream. We
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 // need to compensate by adding one to calculate the length.
Steve Block3ce2e202009-11-05 08:53:23 +0000196 int source_len = fun->end_position() - fun->start_position() + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000197 for (int i = 0; i < source_len; i++) {
198 if (stream.has_more()) PrintF("%c", stream.GetNext());
199 }
200 PrintF("\n\n");
201 }
202 PrintF("--- Code ---\n");
Steve Block3ce2e202009-11-05 08:53:23 +0000203 code->Disassemble(*fun->name()->ToCString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 }
205#endif // ENABLE_DISASSEMBLER
206
207 if (!code.is_null()) {
208 Counters::total_compiled_code_size.Increment(code->instruction_size());
209 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 return code;
211}
212
213
Steve Block3ce2e202009-11-05 08:53:23 +0000214// Generate the code. Takes a function literal, generates code for it, assemble
215// all the pieces into a Code object. This function is only to be called by
216// the compiler.cc code.
217Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun,
218 Handle<Script> script,
Leon Clarke4515c472010-02-03 11:58:03 +0000219 bool is_eval,
220 CompilationInfo* info) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000221 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
222 int len = String::cast(script->source())->length();
223 Counters::total_old_codegen_source_size.Increment(len);
224 }
Steve Block3ce2e202009-11-05 08:53:23 +0000225 MakeCodePrologue(fun);
226 // Generate code.
227 const int kInitialBufferSize = 4 * KB;
Leon Clarke4515c472010-02-03 11:58:03 +0000228 MacroAssembler masm(NULL, kInitialBufferSize);
229 CodeGenerator cgen(&masm, script, is_eval);
Steve Block3ce2e202009-11-05 08:53:23 +0000230 CodeGeneratorScope scope(&cgen);
Leon Clarke4515c472010-02-03 11:58:03 +0000231 cgen.Generate(fun, PRIMARY, info);
Steve Block3ce2e202009-11-05 08:53:23 +0000232 if (cgen.HasStackOverflow()) {
233 ASSERT(!Top::has_pending_exception());
234 return Handle<Code>::null();
235 }
236
237 InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP;
238 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop);
239 return MakeCodeEpilogue(fun, cgen.masm(), flags, script);
240}
241
242
Steve Blocka7e24c12009-10-30 11:49:00 +0000243#ifdef ENABLE_LOGGING_AND_PROFILING
244
245bool CodeGenerator::ShouldGenerateLog(Expression* type) {
246 ASSERT(type != NULL);
247 if (!Logger::is_logging()) return false;
248 Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
249 if (FLAG_log_regexp) {
250 static Vector<const char> kRegexp = CStrVector("regexp");
251 if (name->IsEqualTo(kRegexp))
252 return true;
253 }
254 return false;
255}
256
257#endif
258
259
Steve Blocka7e24c12009-10-30 11:49:00 +0000260Handle<Code> CodeGenerator::ComputeCallInitialize(
261 int argc,
262 InLoopFlag in_loop) {
263 if (in_loop == IN_LOOP) {
264 // Force the creation of the corresponding stub outside loops,
265 // because it may be used when clearing the ICs later - it is
266 // possible for a series of IC transitions to lose the in-loop
267 // information, and the IC clearing code can't generate a stub
268 // that it needs so we need to ensure it is generated already.
269 ComputeCallInitialize(argc, NOT_IN_LOOP);
270 }
271 CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc, in_loop), Code);
272}
273
274
275void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
276 int length = declarations->length();
277 int globals = 0;
278 for (int i = 0; i < length; i++) {
279 Declaration* node = declarations->at(i);
280 Variable* var = node->proxy()->var();
281 Slot* slot = var->slot();
282
283 // If it was not possible to allocate the variable at compile
284 // time, we need to "declare" it at runtime to make sure it
285 // actually exists in the local context.
286 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
287 VisitDeclaration(node);
288 } else {
289 // Count global variables and functions for later processing
290 globals++;
291 }
292 }
293
294 // Return in case of no declared global functions or variables.
295 if (globals == 0) return;
296
297 // Compute array of global variable and function declarations.
298 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
299 for (int j = 0, i = 0; i < length; i++) {
300 Declaration* node = declarations->at(i);
301 Variable* var = node->proxy()->var();
302 Slot* slot = var->slot();
303
304 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
305 // Skip - already processed.
306 } else {
307 array->set(j++, *(var->name()));
308 if (node->fun() == NULL) {
309 if (var->mode() == Variable::CONST) {
310 // In case this is const property use the hole.
311 array->set_the_hole(j++);
312 } else {
313 array->set_undefined(j++);
314 }
315 } else {
Steve Blockd0582a62009-12-15 09:54:21 +0000316 Handle<JSFunction> function =
317 Compiler::BuildBoilerplate(node->fun(), script(), this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 // Check for stack-overflow exception.
319 if (HasStackOverflow()) return;
320 array->set(j++, *function);
321 }
322 }
323 }
324
325 // Invoke the platform-dependent code generator to do the actual
326 // declaration the global variables and functions.
327 DeclareGlobals(array);
328}
329
330
331
332// Special cases: These 'runtime calls' manipulate the current
333// frame and are only used 1 or two places, so we generate them
334// inline instead of generating calls to them. They are used
335// for implementing Function.prototype.call() and
336// Function.prototype.apply().
337CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
338 {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
339 {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
340 {&CodeGenerator::GenerateIsArray, "_IsArray"},
341 {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
342 {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
343 {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
344 {&CodeGenerator::GenerateClassOf, "_ClassOf"},
345 {&CodeGenerator::GenerateValueOf, "_ValueOf"},
346 {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
347 {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
348 {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
349 {&CodeGenerator::GenerateLog, "_Log"},
350 {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
Steve Blockd0582a62009-12-15 09:54:21 +0000351 {&CodeGenerator::GenerateIsObject, "_IsObject"},
352 {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
Leon Clarked91b9f72010-01-27 17:25:45 +0000353 {&CodeGenerator::GenerateIsUndetectableObject, "_IsUndetectableObject"},
Steve Blockd0582a62009-12-15 09:54:21 +0000354 {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
Leon Clarkee46be812010-01-19 14:06:41 +0000355 {&CodeGenerator::GenerateSubString, "_SubString"},
356 {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
357 {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
Steve Blocka7e24c12009-10-30 11:49:00 +0000358};
359
360
361CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT(
362 Handle<String> name) {
363 const int entries_count =
364 sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
365 for (int i = 0; i < entries_count; i++) {
366 InlineRuntimeLUT* entry = &kInlineRuntimeLUT[i];
367 if (name->IsEqualTo(CStrVector(entry->name))) {
368 return entry;
369 }
370 }
371 return NULL;
372}
373
374
375bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
376 ZoneList<Expression*>* args = node->arguments();
377 Handle<String> name = node->name();
378 if (name->length() > 0 && name->Get(0) == '_') {
379 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
380 if (entry != NULL) {
381 ((*this).*(entry->method))(args);
382 return true;
383 }
384 }
385 return false;
386}
387
388
389bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name,
390 const CodeGenerator::InlineRuntimeLUT& new_entry,
391 CodeGenerator::InlineRuntimeLUT* old_entry) {
392 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
393 if (entry == NULL) return false;
394 if (old_entry != NULL) {
395 old_entry->name = entry->name;
396 old_entry->method = entry->method;
397 }
398 entry->name = new_entry.name;
399 entry->method = new_entry.method;
400 return true;
401}
402
403
Steve Block3ce2e202009-11-05 08:53:23 +0000404// Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
405// known result for the test expression, with no side effects.
406CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition(
407 Expression* cond) {
408 if (cond == NULL) return ALWAYS_TRUE;
409
410 Literal* lit = cond->AsLiteral();
411 if (lit == NULL) return DONT_KNOW;
412
413 if (lit->IsTrue()) {
414 return ALWAYS_TRUE;
415 } else if (lit->IsFalse()) {
416 return ALWAYS_FALSE;
417 }
418
419 return DONT_KNOW;
420}
421
422
423void CodeGenerator::RecordPositions(MacroAssembler* masm, int pos) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000424 if (pos != RelocInfo::kNoPosition) {
Steve Block3ce2e202009-11-05 08:53:23 +0000425 masm->RecordStatementPosition(pos);
426 masm->RecordPosition(pos);
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 }
428}
429
430
431void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
Steve Block3ce2e202009-11-05 08:53:23 +0000432 if (FLAG_debug_info) RecordPositions(masm(), fun->start_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000433}
434
435
436void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) {
Steve Block3ce2e202009-11-05 08:53:23 +0000437 if (FLAG_debug_info) RecordPositions(masm(), fun->end_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000438}
439
440
441void CodeGenerator::CodeForStatementPosition(Statement* stmt) {
Steve Block3ce2e202009-11-05 08:53:23 +0000442 if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos());
Steve Blocka7e24c12009-10-30 11:49:00 +0000443}
444
Steve Blockd0582a62009-12-15 09:54:21 +0000445void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
446 if (FLAG_debug_info) RecordPositions(masm(), stmt->condition_position());
447}
Steve Blocka7e24c12009-10-30 11:49:00 +0000448
449void CodeGenerator::CodeForSourcePosition(int pos) {
450 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
451 masm()->RecordPosition(pos);
452 }
453}
454
455
Leon Clarkee46be812010-01-19 14:06:41 +0000456const char* GenericUnaryOpStub::GetName() {
457 switch (op_) {
458 case Token::SUB:
459 return overwrite_
460 ? "GenericUnaryOpStub_SUB_Overwrite"
461 : "GenericUnaryOpStub_SUB_Alloc";
462 case Token::BIT_NOT:
463 return overwrite_
464 ? "GenericUnaryOpStub_BIT_NOT_Overwrite"
465 : "GenericUnaryOpStub_BIT_NOT_Alloc";
466 default:
467 UNREACHABLE();
468 return "<unknown>";
469 }
470}
471
472
Steve Blocka7e24c12009-10-30 11:49:00 +0000473void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
474 switch (type_) {
475 case READ_LENGTH: GenerateReadLength(masm); break;
476 case READ_ELEMENT: GenerateReadElement(masm); break;
477 case NEW_OBJECT: GenerateNewObject(masm); break;
478 }
479}
480
481
Leon Clarke4515c472010-02-03 11:58:03 +0000482int CEntryStub::MinorKey() {
483 ASSERT(result_size_ <= 2);
484#ifdef _WIN64
485 return ExitFrameModeBits::encode(mode_)
486 | IndirectResultBits::encode(result_size_ > 1);
487#else
488 return ExitFrameModeBits::encode(mode_);
489#endif
490}
491
492
Steve Blockd0582a62009-12-15 09:54:21 +0000493bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
494 Object* cache = info()->load_stub_cache();
495 if (cache->IsUndefined()) {
496 return false;
497 } else {
498 *code_out = Code::cast(cache);
499 return true;
500 }
501}
502
503
504void ApiGetterEntryStub::SetCustomCache(Code* value) {
505 info()->set_load_stub_cache(value);
506}
507
Leon Clarke4515c472010-02-03 11:58:03 +0000508#ifdef ENABLE_DEBUGGER_SUPPORT
509void DebuggerStatementStub::Generate(MacroAssembler* masm) {
510 Runtime::Function* f = Runtime::FunctionForId(Runtime::kDebugBreak);
511 masm->TailCallRuntime(ExternalReference(f), 0, f->result_size);
512}
513#endif
514
Steve Blockd0582a62009-12-15 09:54:21 +0000515
Steve Blocka7e24c12009-10-30 11:49:00 +0000516} } // namespace v8::internal