blob: aa2a2b82dffc79e2344859e7d63b99e4a80fbe13 [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,
219 bool is_eval) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000220 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
221 int len = String::cast(script->source())->length();
222 Counters::total_old_codegen_source_size.Increment(len);
223 }
Steve Block3ce2e202009-11-05 08:53:23 +0000224 MakeCodePrologue(fun);
225 // Generate code.
226 const int kInitialBufferSize = 4 * KB;
227 CodeGenerator cgen(kInitialBufferSize, script, is_eval);
228 CodeGeneratorScope scope(&cgen);
229 cgen.GenCode(fun);
230 if (cgen.HasStackOverflow()) {
231 ASSERT(!Top::has_pending_exception());
232 return Handle<Code>::null();
233 }
234
235 InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP;
236 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop);
237 return MakeCodeEpilogue(fun, cgen.masm(), flags, script);
238}
239
240
Steve Blocka7e24c12009-10-30 11:49:00 +0000241#ifdef ENABLE_LOGGING_AND_PROFILING
242
243bool CodeGenerator::ShouldGenerateLog(Expression* type) {
244 ASSERT(type != NULL);
245 if (!Logger::is_logging()) return false;
246 Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
247 if (FLAG_log_regexp) {
248 static Vector<const char> kRegexp = CStrVector("regexp");
249 if (name->IsEqualTo(kRegexp))
250 return true;
251 }
252 return false;
253}
254
255#endif
256
257
Steve Blocka7e24c12009-10-30 11:49:00 +0000258Handle<Code> CodeGenerator::ComputeCallInitialize(
259 int argc,
260 InLoopFlag in_loop) {
261 if (in_loop == IN_LOOP) {
262 // Force the creation of the corresponding stub outside loops,
263 // because it may be used when clearing the ICs later - it is
264 // possible for a series of IC transitions to lose the in-loop
265 // information, and the IC clearing code can't generate a stub
266 // that it needs so we need to ensure it is generated already.
267 ComputeCallInitialize(argc, NOT_IN_LOOP);
268 }
269 CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc, in_loop), Code);
270}
271
272
273void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
274 int length = declarations->length();
275 int globals = 0;
276 for (int i = 0; i < length; i++) {
277 Declaration* node = declarations->at(i);
278 Variable* var = node->proxy()->var();
279 Slot* slot = var->slot();
280
281 // If it was not possible to allocate the variable at compile
282 // time, we need to "declare" it at runtime to make sure it
283 // actually exists in the local context.
284 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
285 VisitDeclaration(node);
286 } else {
287 // Count global variables and functions for later processing
288 globals++;
289 }
290 }
291
292 // Return in case of no declared global functions or variables.
293 if (globals == 0) return;
294
295 // Compute array of global variable and function declarations.
296 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
297 for (int j = 0, i = 0; i < length; i++) {
298 Declaration* node = declarations->at(i);
299 Variable* var = node->proxy()->var();
300 Slot* slot = var->slot();
301
302 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
303 // Skip - already processed.
304 } else {
305 array->set(j++, *(var->name()));
306 if (node->fun() == NULL) {
307 if (var->mode() == Variable::CONST) {
308 // In case this is const property use the hole.
309 array->set_the_hole(j++);
310 } else {
311 array->set_undefined(j++);
312 }
313 } else {
Steve Blockd0582a62009-12-15 09:54:21 +0000314 Handle<JSFunction> function =
315 Compiler::BuildBoilerplate(node->fun(), script(), this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 // Check for stack-overflow exception.
317 if (HasStackOverflow()) return;
318 array->set(j++, *function);
319 }
320 }
321 }
322
323 // Invoke the platform-dependent code generator to do the actual
324 // declaration the global variables and functions.
325 DeclareGlobals(array);
326}
327
328
329
330// Special cases: These 'runtime calls' manipulate the current
331// frame and are only used 1 or two places, so we generate them
332// inline instead of generating calls to them. They are used
333// for implementing Function.prototype.call() and
334// Function.prototype.apply().
335CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
336 {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
337 {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
338 {&CodeGenerator::GenerateIsArray, "_IsArray"},
339 {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
340 {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
341 {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
342 {&CodeGenerator::GenerateClassOf, "_ClassOf"},
343 {&CodeGenerator::GenerateValueOf, "_ValueOf"},
344 {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
345 {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
346 {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
347 {&CodeGenerator::GenerateLog, "_Log"},
348 {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
Steve Blockd0582a62009-12-15 09:54:21 +0000349 {&CodeGenerator::GenerateIsObject, "_IsObject"},
350 {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
Leon Clarked91b9f72010-01-27 17:25:45 +0000351 {&CodeGenerator::GenerateIsUndetectableObject, "_IsUndetectableObject"},
Steve Blockd0582a62009-12-15 09:54:21 +0000352 {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
Leon Clarkee46be812010-01-19 14:06:41 +0000353 {&CodeGenerator::GenerateSubString, "_SubString"},
354 {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
355 {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
Steve Blocka7e24c12009-10-30 11:49:00 +0000356};
357
358
359CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT(
360 Handle<String> name) {
361 const int entries_count =
362 sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
363 for (int i = 0; i < entries_count; i++) {
364 InlineRuntimeLUT* entry = &kInlineRuntimeLUT[i];
365 if (name->IsEqualTo(CStrVector(entry->name))) {
366 return entry;
367 }
368 }
369 return NULL;
370}
371
372
373bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
374 ZoneList<Expression*>* args = node->arguments();
375 Handle<String> name = node->name();
376 if (name->length() > 0 && name->Get(0) == '_') {
377 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
378 if (entry != NULL) {
379 ((*this).*(entry->method))(args);
380 return true;
381 }
382 }
383 return false;
384}
385
386
387bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name,
388 const CodeGenerator::InlineRuntimeLUT& new_entry,
389 CodeGenerator::InlineRuntimeLUT* old_entry) {
390 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
391 if (entry == NULL) return false;
392 if (old_entry != NULL) {
393 old_entry->name = entry->name;
394 old_entry->method = entry->method;
395 }
396 entry->name = new_entry.name;
397 entry->method = new_entry.method;
398 return true;
399}
400
401
Steve Block3ce2e202009-11-05 08:53:23 +0000402// Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
403// known result for the test expression, with no side effects.
404CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition(
405 Expression* cond) {
406 if (cond == NULL) return ALWAYS_TRUE;
407
408 Literal* lit = cond->AsLiteral();
409 if (lit == NULL) return DONT_KNOW;
410
411 if (lit->IsTrue()) {
412 return ALWAYS_TRUE;
413 } else if (lit->IsFalse()) {
414 return ALWAYS_FALSE;
415 }
416
417 return DONT_KNOW;
418}
419
420
421void CodeGenerator::RecordPositions(MacroAssembler* masm, int pos) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 if (pos != RelocInfo::kNoPosition) {
Steve Block3ce2e202009-11-05 08:53:23 +0000423 masm->RecordStatementPosition(pos);
424 masm->RecordPosition(pos);
Steve Blocka7e24c12009-10-30 11:49:00 +0000425 }
426}
427
428
429void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
Steve Block3ce2e202009-11-05 08:53:23 +0000430 if (FLAG_debug_info) RecordPositions(masm(), fun->start_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000431}
432
433
434void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) {
Steve Block3ce2e202009-11-05 08:53:23 +0000435 if (FLAG_debug_info) RecordPositions(masm(), fun->end_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000436}
437
438
439void CodeGenerator::CodeForStatementPosition(Statement* stmt) {
Steve Block3ce2e202009-11-05 08:53:23 +0000440 if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos());
Steve Blocka7e24c12009-10-30 11:49:00 +0000441}
442
Steve Blockd0582a62009-12-15 09:54:21 +0000443void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
444 if (FLAG_debug_info) RecordPositions(masm(), stmt->condition_position());
445}
Steve Blocka7e24c12009-10-30 11:49:00 +0000446
447void CodeGenerator::CodeForSourcePosition(int pos) {
448 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
449 masm()->RecordPosition(pos);
450 }
451}
452
453
454const char* RuntimeStub::GetName() {
455 return Runtime::FunctionForId(id_)->stub_name;
456}
457
458
Leon Clarkee46be812010-01-19 14:06:41 +0000459const char* GenericUnaryOpStub::GetName() {
460 switch (op_) {
461 case Token::SUB:
462 return overwrite_
463 ? "GenericUnaryOpStub_SUB_Overwrite"
464 : "GenericUnaryOpStub_SUB_Alloc";
465 case Token::BIT_NOT:
466 return overwrite_
467 ? "GenericUnaryOpStub_BIT_NOT_Overwrite"
468 : "GenericUnaryOpStub_BIT_NOT_Alloc";
469 default:
470 UNREACHABLE();
471 return "<unknown>";
472 }
473}
474
475
Steve Blocka7e24c12009-10-30 11:49:00 +0000476void RuntimeStub::Generate(MacroAssembler* masm) {
477 Runtime::Function* f = Runtime::FunctionForId(id_);
478 masm->TailCallRuntime(ExternalReference(f),
479 num_arguments_,
480 f->result_size);
481}
482
483
484void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
485 switch (type_) {
486 case READ_LENGTH: GenerateReadLength(masm); break;
487 case READ_ELEMENT: GenerateReadElement(masm); break;
488 case NEW_OBJECT: GenerateNewObject(masm); break;
489 }
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
508
Steve Blocka7e24c12009-10-30 11:49:00 +0000509} } // namespace v8::internal