blob: 483d1e378d49307d84cf1be57a66de7c82fc1da0 [file] [log] [blame]
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001// Copyright 2012 the V8 project authors. All rights reserved.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002// 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
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000030#include "codegen.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000031#include "compiler.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "debug.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000033#include "full-codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000034#include "liveedit.h"
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000035#include "macro-assembler.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "prettyprinter.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000037#include "scopes.h"
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000038#include "scopeinfo.h"
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000039#include "snapshot.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000040#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000041
42namespace v8 {
43namespace internal {
44
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000045void BreakableStatementChecker::Check(Statement* stmt) {
46 Visit(stmt);
47}
48
49
50void BreakableStatementChecker::Check(Expression* expr) {
51 Visit(expr);
52}
53
54
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000055void BreakableStatementChecker::VisitVariableDeclaration(
56 VariableDeclaration* decl) {
57}
58
ulan@chromium.org812308e2012-02-29 15:58:45 +000059void BreakableStatementChecker::VisitFunctionDeclaration(
60 FunctionDeclaration* decl) {
61}
62
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000063void BreakableStatementChecker::VisitModuleDeclaration(
64 ModuleDeclaration* decl) {
65}
66
ulan@chromium.org812308e2012-02-29 15:58:45 +000067void BreakableStatementChecker::VisitImportDeclaration(
68 ImportDeclaration* decl) {
69}
70
71void BreakableStatementChecker::VisitExportDeclaration(
72 ExportDeclaration* decl) {
73}
74
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000075
76void BreakableStatementChecker::VisitModuleLiteral(ModuleLiteral* module) {
77}
78
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000079
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000080void BreakableStatementChecker::VisitModuleVariable(ModuleVariable* module) {
81}
82
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000083
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000084void BreakableStatementChecker::VisitModulePath(ModulePath* module) {
85}
86
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000087
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000088void BreakableStatementChecker::VisitModuleUrl(ModuleUrl* module) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000089}
90
91
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000092void BreakableStatementChecker::VisitModuleStatement(ModuleStatement* stmt) {
93}
94
95
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000096void BreakableStatementChecker::VisitBlock(Block* stmt) {
97}
98
99
100void BreakableStatementChecker::VisitExpressionStatement(
101 ExpressionStatement* stmt) {
102 // Check if expression is breakable.
103 Visit(stmt->expression());
104}
105
106
107void BreakableStatementChecker::VisitEmptyStatement(EmptyStatement* stmt) {
108}
109
110
111void BreakableStatementChecker::VisitIfStatement(IfStatement* stmt) {
112 // If the condition is breakable the if statement is breakable.
113 Visit(stmt->condition());
114}
115
116
117void BreakableStatementChecker::VisitContinueStatement(
118 ContinueStatement* stmt) {
119}
120
121
122void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) {
123}
124
125
126void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
127 // Return is breakable if the expression is.
128 Visit(stmt->expression());
129}
130
131
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000132void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000133 Visit(stmt->expression());
134}
135
136
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000137void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
138 // Switch statements breakable if the tag expression is.
139 Visit(stmt->tag());
140}
141
142
143void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
144 // Mark do while as breakable to avoid adding a break slot in front of it.
145 is_breakable_ = true;
146}
147
148
149void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) {
150 // Mark while statements breakable if the condition expression is.
151 Visit(stmt->cond());
152}
153
154
155void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) {
156 // Mark for statements breakable if the condition expression is.
157 if (stmt->cond() != NULL) {
158 Visit(stmt->cond());
159 }
160}
161
162
163void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
164 // Mark for in statements breakable if the enumerable expression is.
165 Visit(stmt->enumerable());
166}
167
168
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000169void BreakableStatementChecker::VisitForOfStatement(ForOfStatement* stmt) {
170 // For-of is breakable because of the next() call.
171 is_breakable_ = true;
172}
173
174
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000175void BreakableStatementChecker::VisitTryCatchStatement(
176 TryCatchStatement* stmt) {
177 // Mark try catch as breakable to avoid adding a break slot in front of it.
178 is_breakable_ = true;
179}
180
181
182void BreakableStatementChecker::VisitTryFinallyStatement(
183 TryFinallyStatement* stmt) {
184 // Mark try finally as breakable to avoid adding a break slot in front of it.
185 is_breakable_ = true;
186}
187
188
189void BreakableStatementChecker::VisitDebuggerStatement(
190 DebuggerStatement* stmt) {
191 // The debugger statement is breakable.
192 is_breakable_ = true;
193}
194
195
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000196void BreakableStatementChecker::VisitCaseClause(CaseClause* clause) {
197}
198
199
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000200void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
201}
202
203
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000204void BreakableStatementChecker::VisitNativeFunctionLiteral(
205 NativeFunctionLiteral* expr) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000206}
207
208
209void BreakableStatementChecker::VisitConditional(Conditional* expr) {
210}
211
212
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000213void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) {
214}
215
216
217void BreakableStatementChecker::VisitLiteral(Literal* expr) {
218}
219
220
221void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
222}
223
224
225void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) {
226}
227
228
229void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
230}
231
232
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000233void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
234 // If assigning to a property (including a global property) the assignment is
235 // breakable.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000236 VariableProxy* proxy = expr->target()->AsVariableProxy();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000237 Property* prop = expr->target()->AsProperty();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000238 if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000239 is_breakable_ = true;
240 return;
241 }
242
243 // Otherwise the assignment is breakable if the assigned value is.
244 Visit(expr->value());
245}
246
247
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000248void BreakableStatementChecker::VisitYield(Yield* expr) {
249 // Yield is breakable if the expression is.
250 Visit(expr->expression());
251}
252
253
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000254void BreakableStatementChecker::VisitThrow(Throw* expr) {
255 // Throw is breakable if the expression is.
256 Visit(expr->exception());
257}
258
259
260void BreakableStatementChecker::VisitProperty(Property* expr) {
261 // Property load is breakable.
262 is_breakable_ = true;
263}
264
265
266void BreakableStatementChecker::VisitCall(Call* expr) {
267 // Function calls both through IC and call stub are breakable.
268 is_breakable_ = true;
269}
270
271
272void BreakableStatementChecker::VisitCallNew(CallNew* expr) {
273 // Function calls through new are breakable.
274 is_breakable_ = true;
275}
276
277
278void BreakableStatementChecker::VisitCallRuntime(CallRuntime* expr) {
279}
280
281
282void BreakableStatementChecker::VisitUnaryOperation(UnaryOperation* expr) {
283 Visit(expr->expression());
284}
285
286
287void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) {
288 Visit(expr->expression());
289}
290
291
292void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
293 Visit(expr->left());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000294 if (expr->op() != Token::AND &&
295 expr->op() != Token::OR) {
296 Visit(expr->right());
297 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000298}
299
300
301void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
302 Visit(expr->left());
303 Visit(expr->right());
304}
305
306
307void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
308}
309
310
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000311#define __ ACCESS_MASM(masm())
312
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000313bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 Isolate* isolate = info->isolate();
ager@chromium.org5c838252010-02-19 08:53:10 +0000315 Handle<Script> script = info->script();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000316 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
317 int len = String::cast(script->source())->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 isolate->counters()->total_full_codegen_source_size()->Increment(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000319 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000320 CodeGenerator::MakeCodePrologue(info, "full");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000321 const int kInitialBufferSize = 4 * KB;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000322 MacroAssembler masm(info->isolate(), NULL, kInitialBufferSize);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000323#ifdef ENABLE_GDB_JIT_INTERFACE
324 masm.positions_recorder()->StartGDBJITLineInfoRecording();
325#endif
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000326 LOG_CODE_EVENT(isolate,
327 CodeStartLinePosInfoRecordEvent(masm.positions_recorder()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000328
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000329 FullCodeGenerator cgen(&masm, info);
yangguo@chromium.org56454712012-02-16 15:33:53 +0000330 cgen.Generate();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000331 if (cgen.HasStackOverflow()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 ASSERT(!isolate->has_pending_exception());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000333 return false;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000334 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000335 unsigned table_offset = cgen.EmitBackEdgeTable();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000336
lrn@chromium.org34e60782011-09-15 07:25:40 +0000337 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000338 Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000339 code->set_optimizable(info->IsOptimizable() &&
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +0000340 !info->function()->dont_optimize() &&
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000341 info->function()->scope()->AllowsLazyCompilation());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000342 cgen.PopulateDeoptimizationData(code);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000343 cgen.PopulateTypeFeedbackInfo(code);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000344 cgen.PopulateTypeFeedbackCells(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000345 code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000346 code->set_handler_table(*cgen.handler_table());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000347#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000348 code->set_compiled_optimizable(info->IsOptimizable());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000349#endif // ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000350 code->set_allow_osr_at_loop_nesting_level(0);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000351 code->set_profiler_ticks(0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000352 code->set_back_edge_table_offset(table_offset);
353 code->set_back_edges_patched_for_osr(false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000354 CodeGenerator::PrintCode(code, info);
rossberg@chromium.orgebeba022013-08-19 09:36:44 +0000355 info->SetCode(code);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000356#ifdef ENABLE_GDB_JIT_INTERFACE
rossberg@chromium.orgebeba022013-08-19 09:36:44 +0000357 if (FLAG_gdbjit) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000358 GDBJITLineInfo* lineinfo =
359 masm.positions_recorder()->DetachGDBJITLineInfo();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000360 GDBJIT(RegisterDetailedLineInfo(*code, lineinfo));
361 }
362#endif
rossberg@chromium.orgebeba022013-08-19 09:36:44 +0000363 void* line_info = masm.positions_recorder()->DetachJITHandlerData();
364 LOG_CODE_EVENT(isolate, CodeEndLinePosInfoRecordEvent(*code, line_info));
365 return true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000366}
367
368
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000369unsigned FullCodeGenerator::EmitBackEdgeTable() {
370 // The back edge table consists of a length (in number of entries)
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000371 // field, and then a sequence of entries. Each entry is a pair of AST id
372 // and code-relative pc offset.
373 masm()->Align(kIntSize);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000374 unsigned offset = masm()->pc_offset();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000375 unsigned length = back_edges_.length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000376 __ dd(length);
377 for (unsigned i = 0; i < length; ++i) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000378 __ dd(back_edges_[i].id.ToInt());
379 __ dd(back_edges_[i].pc);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000380 __ dd(back_edges_[i].loop_depth);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000381 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000382 return offset;
383}
384
385
386void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
387 // Fill in the deoptimization information.
388 ASSERT(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty());
389 if (!info_->HasDeoptimizationSupport()) return;
390 int length = bailout_entries_.length();
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000391 Handle<DeoptimizationOutputData> data = isolate()->factory()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 NewDeoptimizationOutputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000393 for (int i = 0; i < length; i++) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000394 data->SetAstId(i, bailout_entries_[i].id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000395 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state));
396 }
397 code->set_deoptimization_data(*data);
398}
399
400
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000401void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> code) {
402 Handle<TypeFeedbackInfo> info = isolate()->factory()->NewTypeFeedbackInfo();
403 info->set_ic_total_count(ic_total_count_);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000404 ASSERT(!isolate()->heap()->InNewSpace(*info));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000405 code->set_type_feedback_info(*info);
406}
407
408
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000409void FullCodeGenerator::Initialize() {
410 // The generation of debug code must match between the snapshot code and the
411 // code that is generated later. This is assumed by the debugger when it is
412 // calculating PC offsets after generating a debug version of code. Therefore
413 // we disable the production of debug code in the full compiler if we are
414 // either generating a snapshot or we booted from a snapshot.
415 generate_debug_code_ = FLAG_debug_code &&
416 !Serializer::enabled() &&
417 !Snapshot::HaveASnapshotToStartFrom();
418 masm_->set_emit_debug_code(generate_debug_code_);
419 masm_->set_predictable_code_size(true);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000420 InitializeAstVisitor(info_->isolate());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000421}
422
423
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000424void FullCodeGenerator::PopulateTypeFeedbackCells(Handle<Code> code) {
425 if (type_feedback_cells_.is_empty()) return;
426 int length = type_feedback_cells_.length();
427 int array_size = TypeFeedbackCells::LengthOfFixedArray(length);
428 Handle<TypeFeedbackCells> cache = Handle<TypeFeedbackCells>::cast(
429 isolate()->factory()->NewFixedArray(array_size, TENURED));
430 for (int i = 0; i < length; i++) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000431 cache->SetAstId(i, type_feedback_cells_[i].ast_id);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000432 cache->SetCell(i, *type_feedback_cells_[i].cell);
433 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000434 TypeFeedbackInfo::cast(code->type_feedback_info())->set_type_feedback_cells(
435 *cache);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000436}
437
438
439
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000440void FullCodeGenerator::PrepareForBailout(Expression* node, State state) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000441 PrepareForBailoutForId(node->id(), state);
442}
443
444
445void FullCodeGenerator::RecordJSReturnSite(Call* call) {
446 // We record the offset of the function return so we can rebuild the frame
447 // if the function was inlined, i.e., this is the return address in the
448 // inlined function's frame.
449 //
450 // The state is ignored. We defensively set it to TOS_REG, which is the
451 // real state of the unoptimized code at the return site.
452 PrepareForBailoutForId(call->ReturnId(), TOS_REG);
453#ifdef DEBUG
454 // In debug builds, mark the return so we can verify that this function
455 // was called.
456 ASSERT(!call->return_is_recorded_);
457 call->return_is_recorded_ = true;
458#endif
459}
460
461
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000462void FullCodeGenerator::PrepareForBailoutForId(BailoutId id, State state) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000463 // There's no need to prepare this code for bailouts from already optimized
464 // code or code that can't be optimized.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000465 if (!info_->HasDeoptimizationSupport()) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000466 unsigned pc_and_state =
467 StateField::encode(state) | PcField::encode(masm_->pc_offset());
yangguo@chromium.org56454712012-02-16 15:33:53 +0000468 ASSERT(Smi::IsValid(pc_and_state));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000469 BailoutEntry entry = { id, pc_and_state };
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000470 ASSERT(!prepared_bailout_ids_.Contains(id.ToInt()));
471 prepared_bailout_ids_.Add(id.ToInt(), zone());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000472 bailout_entries_.Add(entry, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000473}
474
475
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000476void FullCodeGenerator::RecordTypeFeedbackCell(
danno@chromium.org41728482013-06-12 22:31:22 +0000477 TypeFeedbackId id, Handle<Cell> cell) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000478 TypeFeedbackCellEntry entry = { id, cell };
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000479 type_feedback_cells_.Add(entry, zone());
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000480}
481
482
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000483void FullCodeGenerator::RecordBackEdge(BailoutId ast_id) {
484 // The pc offset does not need to be encoded and packed together with a state.
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000485 ASSERT(masm_->pc_offset() > 0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000486 ASSERT(loop_depth() > 0);
487 uint8_t depth = Min(loop_depth(), Code::kMaxLoopNestingMarker);
488 BackEdgeEntry entry =
489 { ast_id, static_cast<unsigned>(masm_->pc_offset()), depth };
490 back_edges_.Add(entry, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000491}
492
493
ricow@chromium.org65fae842010-08-25 15:26:24 +0000494bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000495 // Inline smi case inside loops, but not division and modulo which
496 // are too complicated and take up too much space.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000497 if (op == Token::DIV ||op == Token::MOD) return false;
498 if (FLAG_always_inline_smi_code) return true;
499 return loop_depth_ > 0;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000500}
501
502
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000503void FullCodeGenerator::EffectContext::Plug(Register reg) const {
504}
505
506
507void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000508 __ Move(result_register(), reg);
509}
510
511
512void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
danno@chromium.org59400602013-08-13 17:09:37 +0000513 __ Push(reg);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000514}
515
516
517void FullCodeGenerator::TestContext::Plug(Register reg) const {
518 // For simplicity we always test the accumulator register.
519 __ Move(result_register(), reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000520 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000521 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000522}
523
524
525void FullCodeGenerator::EffectContext::PlugTOS() const {
526 __ Drop(1);
527}
528
529
530void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
danno@chromium.org59400602013-08-13 17:09:37 +0000531 __ Pop(result_register());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000532}
533
534
535void FullCodeGenerator::StackValueContext::PlugTOS() const {
536}
537
538
539void FullCodeGenerator::TestContext::PlugTOS() const {
540 // For simplicity we always test the accumulator register.
danno@chromium.org59400602013-08-13 17:09:37 +0000541 __ Pop(result_register());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000542 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000543 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000544}
545
546
547void FullCodeGenerator::EffectContext::PrepareTest(
548 Label* materialize_true,
549 Label* materialize_false,
550 Label** if_true,
551 Label** if_false,
552 Label** fall_through) const {
553 // In an effect context, the true and the false case branch to the
554 // same label.
555 *if_true = *if_false = *fall_through = materialize_true;
556}
557
558
559void FullCodeGenerator::AccumulatorValueContext::PrepareTest(
560 Label* materialize_true,
561 Label* materialize_false,
562 Label** if_true,
563 Label** if_false,
564 Label** fall_through) const {
565 *if_true = *fall_through = materialize_true;
566 *if_false = materialize_false;
567}
568
569
570void FullCodeGenerator::StackValueContext::PrepareTest(
571 Label* materialize_true,
572 Label* materialize_false,
573 Label** if_true,
574 Label** if_false,
575 Label** fall_through) const {
576 *if_true = *fall_through = materialize_true;
577 *if_false = materialize_false;
578}
579
580
581void FullCodeGenerator::TestContext::PrepareTest(
582 Label* materialize_true,
583 Label* materialize_false,
584 Label** if_true,
585 Label** if_false,
586 Label** fall_through) const {
587 *if_true = true_label_;
588 *if_false = false_label_;
589 *fall_through = fall_through_;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000590}
591
592
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000593void FullCodeGenerator::DoTest(const TestContext* context) {
594 DoTest(context->condition(),
595 context->true_label(),
596 context->false_label(),
597 context->fall_through());
598}
599
600
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000601void FullCodeGenerator::AllocateModules(ZoneList<Declaration*>* declarations) {
602 ASSERT(scope_->is_global_scope());
603
604 for (int i = 0; i < declarations->length(); i++) {
605 ModuleDeclaration* declaration = declarations->at(i)->AsModuleDeclaration();
606 if (declaration != NULL) {
607 ModuleLiteral* module = declaration->module()->AsModuleLiteral();
608 if (module != NULL) {
609 Comment cmnt(masm_, "[ Link nested modules");
610 Scope* scope = module->body()->scope();
611 Interface* interface = scope->interface();
612 ASSERT(interface->IsModule() && interface->IsFrozen());
613
614 interface->Allocate(scope->module_var()->index());
615
616 // Set up module context.
617 ASSERT(scope->interface()->Index() >= 0);
618 __ Push(Smi::FromInt(scope->interface()->Index()));
619 __ Push(scope->GetScopeInfo());
620 __ CallRuntime(Runtime::kPushModuleContext, 2);
621 StoreToFrameField(StandardFrameConstants::kContextOffset,
622 context_register());
623
624 AllocateModules(scope->declarations());
625
626 // Pop module context.
627 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
628 // Update local stack frame context field.
629 StoreToFrameField(StandardFrameConstants::kContextOffset,
630 context_register());
631 }
632 }
633 }
634}
635
636
637// Modules have their own local scope, represented by their own context.
638// Module instance objects have an accessor for every export that forwards
639// access to the respective slot from the module's context. (Exports that are
640// modules themselves, however, are simple data properties.)
641//
642// All modules have a _hosting_ scope/context, which (currently) is the
643// (innermost) enclosing global scope. To deal with recursion, nested modules
644// are hosted by the same scope as global ones.
645//
646// For every (global or nested) module literal, the hosting context has an
647// internal slot that points directly to the respective module context. This
648// enables quick access to (statically resolved) module members by 2-dimensional
649// access through the hosting context. For example,
650//
651// module A {
652// let x;
653// module B { let y; }
654// }
655// module C { let z; }
656//
657// allocates contexts as follows:
658//
659// [header| .A | .B | .C | A | C ] (global)
660// | | |
661// | | +-- [header| z ] (module)
662// | |
663// | +------- [header| y ] (module)
664// |
665// +------------ [header| x | B ] (module)
666//
667// Here, .A, .B, .C are the internal slots pointing to the hosted module
668// contexts, whereas A, B, C hold the actual instance objects (note that every
669// module context also points to the respective instance object through its
670// extension slot in the header).
671//
672// To deal with arbitrary recursion and aliases between modules,
673// they are created and initialized in several stages. Each stage applies to
674// all modules in the hosting global scope, including nested ones.
675//
676// 1. Allocate: for each module _literal_, allocate the module contexts and
677// respective instance object and wire them up. This happens in the
678// PushModuleContext runtime function, as generated by AllocateModules
679// (invoked by VisitDeclarations in the hosting scope).
680//
681// 2. Bind: for each module _declaration_ (i.e. literals as well as aliases),
682// assign the respective instance object to respective local variables. This
683// happens in VisitModuleDeclaration, and uses the instance objects created
684// in the previous stage.
685// For each module _literal_, this phase also constructs a module descriptor
686// for the next stage. This happens in VisitModuleLiteral.
687//
688// 3. Populate: invoke the DeclareModules runtime function to populate each
689// _instance_ object with accessors for it exports. This is generated by
690// DeclareModules (invoked by VisitDeclarations in the hosting scope again),
691// and uses the descriptors generated in the previous stage.
692//
693// 4. Initialize: execute the module bodies (and other code) in sequence. This
694// happens by the separate statements generated for module bodies. To reenter
695// the module scopes properly, the parser inserted ModuleStatements.
696
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000697void FullCodeGenerator::VisitDeclarations(
698 ZoneList<Declaration*>* declarations) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000699 Handle<FixedArray> saved_modules = modules_;
700 int saved_module_index = module_index_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000701 ZoneList<Handle<Object> >* saved_globals = globals_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000702 ZoneList<Handle<Object> > inner_globals(10, zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000703 globals_ = &inner_globals;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000704
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000705 if (scope_->num_modules() != 0) {
706 // This is a scope hosting modules. Allocate a descriptor array to pass
707 // to the runtime for initialization.
708 Comment cmnt(masm_, "[ Allocate modules");
709 ASSERT(scope_->is_global_scope());
710 modules_ =
711 isolate()->factory()->NewFixedArray(scope_->num_modules(), TENURED);
712 module_index_ = 0;
713
714 // Generate code for allocating all modules, including nested ones.
715 // The allocated contexts are stored in internal variables in this scope.
716 AllocateModules(declarations);
717 }
718
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000719 AstVisitor::VisitDeclarations(declarations);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000720
721 if (scope_->num_modules() != 0) {
722 // Initialize modules from descriptor array.
723 ASSERT(module_index_ == modules_->length());
724 DeclareModules(modules_);
725 modules_ = saved_modules;
726 module_index_ = saved_module_index;
727 }
728
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000729 if (!globals_->is_empty()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000730 // Invoke the platform-dependent code generator to do the actual
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000731 // declaration of the global functions and variables.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000732 Handle<FixedArray> array =
733 isolate()->factory()->NewFixedArray(globals_->length(), TENURED);
734 for (int i = 0; i < globals_->length(); ++i)
735 array->set(i, *globals_->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000736 DeclareGlobals(array);
737 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000738
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000739 globals_ = saved_globals;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000740}
741
742
743void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000744 Block* block = module->body();
745 Scope* saved_scope = scope();
746 scope_ = block->scope();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000747 Interface* interface = scope_->interface();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000748
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000749 Comment cmnt(masm_, "[ ModuleLiteral");
750 SetStatementPosition(block);
751
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000752 ASSERT(!modules_.is_null());
753 ASSERT(module_index_ < modules_->length());
754 int index = module_index_++;
755
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000756 // Set up module context.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000757 ASSERT(interface->Index() >= 0);
758 __ Push(Smi::FromInt(interface->Index()));
759 __ Push(Smi::FromInt(0));
760 __ CallRuntime(Runtime::kPushModuleContext, 2);
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000761 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000762
763 {
764 Comment cmnt(masm_, "[ Declarations");
765 VisitDeclarations(scope_->declarations());
766 }
767
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000768 // Populate the module description.
769 Handle<ModuleInfo> description =
770 ModuleInfo::Create(isolate(), interface, scope_);
771 modules_->set(index, *description);
772
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000773 scope_ = saved_scope;
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000774 // Pop module context.
775 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
776 // Update local stack frame context field.
777 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000778}
779
780
781void FullCodeGenerator::VisitModuleVariable(ModuleVariable* module) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000782 // Nothing to do.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000783 // The instance object is resolved statically through the module's interface.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000784}
785
786
787void FullCodeGenerator::VisitModulePath(ModulePath* module) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000788 // Nothing to do.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000789 // The instance object is resolved statically through the module's interface.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000790}
791
792
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000793void FullCodeGenerator::VisitModuleUrl(ModuleUrl* module) {
794 // TODO(rossberg): dummy allocation for now.
795 Scope* scope = module->body()->scope();
796 Interface* interface = scope_->interface();
797
798 ASSERT(interface->IsModule() && interface->IsFrozen());
799 ASSERT(!modules_.is_null());
800 ASSERT(module_index_ < modules_->length());
801 interface->Allocate(scope->module_var()->index());
802 int index = module_index_++;
803
804 Handle<ModuleInfo> description =
805 ModuleInfo::Create(isolate(), interface, scope_);
806 modules_->set(index, *description);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000807}
808
809
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000810int FullCodeGenerator::DeclareGlobalsFlags() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000811 ASSERT(DeclareGlobalsLanguageMode::is_valid(language_mode()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000812 return DeclareGlobalsEvalFlag::encode(is_eval()) |
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000813 DeclareGlobalsNativeFlag::encode(is_native()) |
814 DeclareGlobalsLanguageMode::encode(language_mode());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000815}
816
817
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000818void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000819 CodeGenerator::RecordPositions(masm_, fun->start_position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000820}
821
822
823void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000824 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000825}
826
827
828void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000829#ifdef ENABLE_DEBUGGER_SUPPORT
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000830 if (!isolate()->debugger()->IsDebuggerActive()) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000831 CodeGenerator::RecordPositions(masm_, stmt->position());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000832 } else {
833 // Check if the statement will be breakable without adding a debug break
834 // slot.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000835 BreakableStatementChecker checker(isolate());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000836 checker.Check(stmt);
837 // Record the statement position right here if the statement is not
838 // breakable. For breakable statements the actual recording of the
839 // position will be postponed to the breakable code (typically an IC).
840 bool position_recorded = CodeGenerator::RecordPositions(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000841 masm_, stmt->position(), !checker.is_breakable());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000842 // If the position recording did record a new position generate a debug
843 // break slot to make the statement breakable.
844 if (position_recorded) {
845 Debug::GenerateSlot(masm_);
846 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000847 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000848#else
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000849 CodeGenerator::RecordPositions(masm_, stmt->position());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000850#endif
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000851}
852
853
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000854void FullCodeGenerator::SetExpressionPosition(Expression* expr) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000855#ifdef ENABLE_DEBUGGER_SUPPORT
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000856 if (!isolate()->debugger()->IsDebuggerActive()) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000857 CodeGenerator::RecordPositions(masm_, expr->position());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000858 } else {
859 // Check if the expression will be breakable without adding a debug break
860 // slot.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000861 BreakableStatementChecker checker(isolate());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000862 checker.Check(expr);
863 // Record a statement position right here if the expression is not
864 // breakable. For breakable expressions the actual recording of the
865 // position will be postponed to the breakable code (typically an IC).
866 // NOTE this will record a statement position for something which might
867 // not be a statement. As stepping in the debugger will only stop at
868 // statement positions this is used for e.g. the condition expression of
869 // a do while loop.
870 bool position_recorded = CodeGenerator::RecordPositions(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000871 masm_, expr->position(), !checker.is_breakable());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000872 // If the position recording did record a new position generate a debug
873 // break slot to make the statement breakable.
874 if (position_recorded) {
875 Debug::GenerateSlot(masm_);
876 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000877 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000878#else
879 CodeGenerator::RecordPositions(masm_, pos);
880#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000881}
882
883
884void FullCodeGenerator::SetStatementPosition(int pos) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000885 CodeGenerator::RecordPositions(masm_, pos);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000886}
887
888
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000889void FullCodeGenerator::SetSourcePosition(int pos) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000890 if (pos != RelocInfo::kNoPosition) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000891 masm_->positions_recorder()->RecordPosition(pos);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000892 }
893}
894
895
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000896// Lookup table for code generators for special runtime calls which are
897// generated inline.
898#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
899 &FullCodeGenerator::Emit##Name,
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000900
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000901const FullCodeGenerator::InlineFunctionGenerator
902 FullCodeGenerator::kInlineFunctionGenerators[] = {
903 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
904 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
905 };
906#undef INLINE_FUNCTION_GENERATOR_ADDRESS
907
908
909FullCodeGenerator::InlineFunctionGenerator
910 FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000911 int lookup_index =
912 static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction);
913 ASSERT(lookup_index >= 0);
914 ASSERT(static_cast<size_t>(lookup_index) <
915 ARRAY_SIZE(kInlineFunctionGenerators));
916 return kInlineFunctionGenerators[lookup_index];
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000917}
918
919
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000920void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
921 const Runtime::Function* function = expr->function();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000922 ASSERT(function != NULL);
923 ASSERT(function->intrinsic_type == Runtime::INLINE);
924 InlineFunctionGenerator generator =
925 FindInlineFunctionGenerator(function->function_id);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000926 ((*this).*(generator))(expr);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000927}
928
929
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000930void FullCodeGenerator::EmitGeneratorNext(CallRuntime* expr) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000931 ZoneList<Expression*>* args = expr->arguments();
932 ASSERT(args->length() == 2);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000933 EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::NEXT);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000934}
935
936
937void FullCodeGenerator::EmitGeneratorThrow(CallRuntime* expr) {
938 ZoneList<Expression*>* args = expr->arguments();
939 ASSERT(args->length() == 2);
940 EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::THROW);
941}
942
943
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000944void FullCodeGenerator::EmitDebugBreakInOptimizedCode(CallRuntime* expr) {
945 context()->Plug(handle(Smi::FromInt(0), isolate()));
946}
947
948
ricow@chromium.org65fae842010-08-25 15:26:24 +0000949void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000950 switch (expr->op()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000951 case Token::COMMA:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000952 return VisitComma(expr);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000953 case Token::OR:
954 case Token::AND:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000955 return VisitLogicalExpression(expr);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000956 default:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000957 return VisitArithmeticExpression(expr);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000958 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000959}
960
961
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000962void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) {
963 if (context()->IsEffect()) {
964 VisitForEffect(expr);
965 } else if (context()->IsAccumulatorValue()) {
966 VisitForAccumulatorValue(expr);
967 } else if (context()->IsStackValue()) {
968 VisitForStackValue(expr);
969 } else if (context()->IsTest()) {
970 const TestContext* test = TestContext::cast(context());
971 VisitForControl(expr, test->true_label(), test->false_label(),
972 test->fall_through());
973 }
974}
975
976
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000977void FullCodeGenerator::VisitComma(BinaryOperation* expr) {
978 Comment cmnt(masm_, "[ Comma");
979 VisitForEffect(expr->left());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000980 VisitInDuplicateContext(expr->right());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000981}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000982
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000983
984void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
985 bool is_logical_and = expr->op() == Token::AND;
986 Comment cmnt(masm_, is_logical_and ? "[ Logical AND" : "[ Logical OR");
987 Expression* left = expr->left();
988 Expression* right = expr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000989 BailoutId right_id = expr->RightId();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000990 Label done;
991
992 if (context()->IsTest()) {
993 Label eval_right;
994 const TestContext* test = TestContext::cast(context());
995 if (is_logical_and) {
996 VisitForControl(left, &eval_right, test->false_label(), &eval_right);
997 } else {
998 VisitForControl(left, test->true_label(), &eval_right, &eval_right);
999 }
1000 PrepareForBailoutForId(right_id, NO_REGISTERS);
1001 __ bind(&eval_right);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001002
1003 } else if (context()->IsAccumulatorValue()) {
1004 VisitForAccumulatorValue(left);
1005 // We want the value in the accumulator for the test, and on the stack in
1006 // case we need it.
danno@chromium.org59400602013-08-13 17:09:37 +00001007 __ Push(result_register());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001008 Label discard, restore;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001009 if (is_logical_and) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001010 DoTest(left, &discard, &restore, &restore);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001011 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001012 DoTest(left, &restore, &discard, &restore);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001013 }
1014 __ bind(&restore);
danno@chromium.org59400602013-08-13 17:09:37 +00001015 __ Pop(result_register());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001016 __ jmp(&done);
1017 __ bind(&discard);
1018 __ Drop(1);
1019 PrepareForBailoutForId(right_id, NO_REGISTERS);
1020
1021 } else if (context()->IsStackValue()) {
1022 VisitForAccumulatorValue(left);
1023 // We want the value in the accumulator for the test, and on the stack in
1024 // case we need it.
danno@chromium.org59400602013-08-13 17:09:37 +00001025 __ Push(result_register());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001026 Label discard;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001027 if (is_logical_and) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001028 DoTest(left, &discard, &done, &discard);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001029 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001030 DoTest(left, &done, &discard, &discard);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001031 }
1032 __ bind(&discard);
1033 __ Drop(1);
1034 PrepareForBailoutForId(right_id, NO_REGISTERS);
1035
1036 } else {
1037 ASSERT(context()->IsEffect());
1038 Label eval_right;
1039 if (is_logical_and) {
1040 VisitForControl(left, &eval_right, &done, &eval_right);
1041 } else {
1042 VisitForControl(left, &done, &eval_right, &eval_right);
1043 }
1044 PrepareForBailoutForId(right_id, NO_REGISTERS);
1045 __ bind(&eval_right);
1046 }
1047
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001048 VisitInDuplicateContext(right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001049 __ bind(&done);
1050}
1051
1052
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001053void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
1054 Token::Value op = expr->op();
1055 Comment cmnt(masm_, "[ ArithmeticExpression");
1056 Expression* left = expr->left();
1057 Expression* right = expr->right();
1058 OverwriteMode mode =
1059 left->ResultOverwriteAllowed()
1060 ? OVERWRITE_LEFT
1061 : (right->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE);
1062
1063 VisitForStackValue(left);
1064 VisitForAccumulatorValue(right);
1065
1066 SetSourcePosition(expr->position());
1067 if (ShouldInlineSmiCase(op)) {
1068 EmitInlineSmiBinaryOp(expr, op, mode, left, right);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001069 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001070 EmitBinaryOp(expr, op, mode);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001071 }
1072}
1073
1074
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001075void FullCodeGenerator::VisitBlock(Block* stmt) {
1076 Comment cmnt(masm_, "[ Block");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001077 NestedBlock nested_block(this, stmt);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001078 SetStatementPosition(stmt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001079
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001080 Scope* saved_scope = scope();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001081 // Push a block context when entering a block with block scoped variables.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001082 if (stmt->scope() != NULL) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001083 scope_ = stmt->scope();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001084 ASSERT(!scope_->is_module_scope());
1085 { Comment cmnt(masm_, "[ Extend block context");
1086 Handle<ScopeInfo> scope_info = scope_->GetScopeInfo();
1087 int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS;
1088 __ Push(scope_info);
1089 PushFunctionArgumentForContextAllocation();
1090 if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) {
1091 FastNewBlockContextStub stub(heap_slots);
1092 __ CallStub(&stub);
1093 } else {
1094 __ CallRuntime(Runtime::kPushBlockContext, 2);
1095 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001096
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001097 // Replace the context stored in the frame.
1098 StoreToFrameField(StandardFrameConstants::kContextOffset,
1099 context_register());
1100 }
1101 { Comment cmnt(masm_, "[ Declarations");
1102 VisitDeclarations(scope_->declarations());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001103 }
1104 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001105
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001106 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001107 VisitStatements(stmt->statements());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001108 scope_ = saved_scope;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001109 __ bind(nested_block.break_label());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001110 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001111
1112 // Pop block context if necessary.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001113 if (stmt->scope() != NULL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001114 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1115 // Update local stack frame context field.
1116 StoreToFrameField(StandardFrameConstants::kContextOffset,
1117 context_register());
1118 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001119}
1120
1121
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001122void FullCodeGenerator::VisitModuleStatement(ModuleStatement* stmt) {
1123 Comment cmnt(masm_, "[ Module context");
1124
1125 __ Push(Smi::FromInt(stmt->proxy()->interface()->Index()));
1126 __ Push(Smi::FromInt(0));
1127 __ CallRuntime(Runtime::kPushModuleContext, 2);
1128 StoreToFrameField(
1129 StandardFrameConstants::kContextOffset, context_register());
1130
1131 Scope* saved_scope = scope_;
1132 scope_ = stmt->body()->scope();
1133 VisitStatements(stmt->body()->statements());
1134 scope_ = saved_scope;
1135 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1136 // Update local stack frame context field.
1137 StoreToFrameField(StandardFrameConstants::kContextOffset,
1138 context_register());
1139}
1140
1141
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001142void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
1143 Comment cmnt(masm_, "[ ExpressionStatement");
1144 SetStatementPosition(stmt);
1145 VisitForEffect(stmt->expression());
1146}
1147
1148
1149void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
1150 Comment cmnt(masm_, "[ EmptyStatement");
1151 SetStatementPosition(stmt);
1152}
1153
1154
1155void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
1156 Comment cmnt(masm_, "[ IfStatement");
1157 SetStatementPosition(stmt);
1158 Label then_part, else_part, done;
1159
ricow@chromium.org65fae842010-08-25 15:26:24 +00001160 if (stmt->HasElseStatement()) {
1161 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001162 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001163 __ bind(&then_part);
1164 Visit(stmt->then_statement());
1165 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001166
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001167 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001168 __ bind(&else_part);
1169 Visit(stmt->else_statement());
1170 } else {
1171 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001172 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001173 __ bind(&then_part);
1174 Visit(stmt->then_statement());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001175
1176 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001177 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001178 __ bind(&done);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001179 PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001180}
1181
1182
1183void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
1184 Comment cmnt(masm_, "[ ContinueStatement");
1185 SetStatementPosition(stmt);
1186 NestedStatement* current = nesting_stack_;
1187 int stack_depth = 0;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001188 int context_length = 0;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001189 // When continuing, we clobber the unpredictable value in the accumulator
1190 // with one that's safe for GC. If we hit an exit from the try block of
1191 // try...finally on our way out, we will unconditionally preserve the
1192 // accumulator on the stack.
1193 ClearAccumulator();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001194 while (!current->IsContinueTarget(stmt->target())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001195 current = current->Exit(&stack_depth, &context_length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001196 }
1197 __ Drop(stack_depth);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001198 if (context_length > 0) {
1199 while (context_length > 0) {
1200 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1201 --context_length;
1202 }
1203 StoreToFrameField(StandardFrameConstants::kContextOffset,
1204 context_register());
1205 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001206
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001207 __ jmp(current->AsIteration()->continue_label());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001208}
1209
1210
1211void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
1212 Comment cmnt(masm_, "[ BreakStatement");
1213 SetStatementPosition(stmt);
1214 NestedStatement* current = nesting_stack_;
1215 int stack_depth = 0;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001216 int context_length = 0;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001217 // When breaking, we clobber the unpredictable value in the accumulator
1218 // with one that's safe for GC. If we hit an exit from the try block of
1219 // try...finally on our way out, we will unconditionally preserve the
1220 // accumulator on the stack.
1221 ClearAccumulator();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001222 while (!current->IsBreakTarget(stmt->target())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001223 current = current->Exit(&stack_depth, &context_length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001224 }
1225 __ Drop(stack_depth);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001226 if (context_length > 0) {
1227 while (context_length > 0) {
1228 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1229 --context_length;
1230 }
1231 StoreToFrameField(StandardFrameConstants::kContextOffset,
1232 context_register());
1233 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001234
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001235 __ jmp(current->AsBreakable()->break_label());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001236}
1237
1238
danno@chromium.org41728482013-06-12 22:31:22 +00001239void FullCodeGenerator::EmitUnwindBeforeReturn() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001240 NestedStatement* current = nesting_stack_;
1241 int stack_depth = 0;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001242 int context_length = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001243 while (current != NULL) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001244 current = current->Exit(&stack_depth, &context_length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001245 }
1246 __ Drop(stack_depth);
danno@chromium.org41728482013-06-12 22:31:22 +00001247}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001248
danno@chromium.org41728482013-06-12 22:31:22 +00001249
1250void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
1251 Comment cmnt(masm_, "[ ReturnStatement");
1252 SetStatementPosition(stmt);
1253 Expression* expr = stmt->expression();
1254 VisitForAccumulatorValue(expr);
1255 EmitUnwindBeforeReturn();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001256 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001257}
1258
1259
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001260void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
1261 Comment cmnt(masm_, "[ WithStatement");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001262 SetStatementPosition(stmt);
1263
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001264 VisitForStackValue(stmt->expression());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001265 PushFunctionArgumentForContextAllocation();
1266 __ CallRuntime(Runtime::kPushWithContext, 2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001267 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001268
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001269 Scope* saved_scope = scope();
1270 scope_ = stmt->scope();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001271 { WithOrCatch body(this);
1272 Visit(stmt->statement());
1273 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001274 scope_ = saved_scope;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001275
1276 // Pop context.
1277 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1278 // Update local stack frame context field.
1279 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001280}
1281
1282
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001283void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
1284 Comment cmnt(masm_, "[ DoWhileStatement");
1285 SetStatementPosition(stmt);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001286 Label body, book_keeping;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001287
1288 Iteration loop_statement(this, stmt);
1289 increment_loop_depth();
1290
1291 __ bind(&body);
1292 Visit(stmt->body());
1293
ricow@chromium.org65fae842010-08-25 15:26:24 +00001294 // Record the position of the do while condition and make sure it is
1295 // possible to break on the condition.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001296 __ bind(loop_statement.continue_label());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001297 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001298 SetExpressionPosition(stmt->cond());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001299 VisitForControl(stmt->cond(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001300 &book_keeping,
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001301 loop_statement.break_label(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001302 &book_keeping);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001303
1304 // Check stack before looping.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001305 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001306 __ bind(&book_keeping);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001307 EmitBackEdgeBookkeeping(stmt, &body);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001308 __ jmp(&body);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001309
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001310 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001311 __ bind(loop_statement.break_label());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001312 decrement_loop_depth();
1313}
1314
1315
1316void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
1317 Comment cmnt(masm_, "[ WhileStatement");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001318 Label test, body;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001319
1320 Iteration loop_statement(this, stmt);
1321 increment_loop_depth();
1322
1323 // Emit the test at the bottom of the loop.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001324 __ jmp(&test);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001325
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001326 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001327 __ bind(&body);
1328 Visit(stmt->body());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001329
1330 // Emit the statement position here as this is where the while
1331 // statement code starts.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001332 __ bind(loop_statement.continue_label());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001333 SetStatementPosition(stmt);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001334
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001335 // Check stack before looping.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001336 EmitBackEdgeBookkeeping(stmt, &body);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001337
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001338 __ bind(&test);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001339 VisitForControl(stmt->cond(),
1340 &body,
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001341 loop_statement.break_label(),
1342 loop_statement.break_label());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001343
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001344 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001345 __ bind(loop_statement.break_label());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001346 decrement_loop_depth();
1347}
1348
1349
1350void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
1351 Comment cmnt(masm_, "[ ForStatement");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001352 Label test, body;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001353
1354 Iteration loop_statement(this, stmt);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001355
1356 // Set statement position for a break slot before entering the for-body.
1357 SetStatementPosition(stmt);
1358
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001359 if (stmt->init() != NULL) {
1360 Visit(stmt->init());
1361 }
1362
1363 increment_loop_depth();
1364 // Emit the test at the bottom of the loop (even if empty).
1365 __ jmp(&test);
1366
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001367 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001368 __ bind(&body);
1369 Visit(stmt->body());
1370
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001371 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001372 __ bind(loop_statement.continue_label());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001373 if (stmt->next() != NULL) {
1374 Visit(stmt->next());
1375 }
1376
ricow@chromium.org65fae842010-08-25 15:26:24 +00001377 // Emit the statement position here as this is where the for
1378 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001379 SetStatementPosition(stmt);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001380
1381 // Check stack before looping.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001382 EmitBackEdgeBookkeeping(stmt, &body);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001383
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001384 __ bind(&test);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001385 if (stmt->cond() != NULL) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001386 VisitForControl(stmt->cond(),
1387 &body,
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001388 loop_statement.break_label(),
1389 loop_statement.break_label());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001390 } else {
1391 __ jmp(&body);
1392 }
1393
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001394 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001395 __ bind(loop_statement.break_label());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001396 decrement_loop_depth();
1397}
1398
1399
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001400void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1401 Comment cmnt(masm_, "[ TryCatchStatement");
1402 SetStatementPosition(stmt);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001403 // The try block adds a handler to the exception handler chain before
1404 // entering, and removes it again when exiting normally. If an exception
1405 // is thrown during execution of the try block, the handler is consumed
1406 // and control is passed to the catch block with the exception in the
1407 // result register.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001408
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001409 Label try_entry, handler_entry, exit;
1410 __ jmp(&try_entry);
1411 __ bind(&handler_entry);
1412 handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
1413 // Exception handler code, the exception is in the result register.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001414 // Extend the context before executing the catch block.
1415 { Comment cmnt(masm_, "[ Extend catch context");
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001416 __ Push(stmt->variable()->name());
danno@chromium.org59400602013-08-13 17:09:37 +00001417 __ Push(result_register());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001418 PushFunctionArgumentForContextAllocation();
1419 __ CallRuntime(Runtime::kPushCatchContext, 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001420 StoreToFrameField(StandardFrameConstants::kContextOffset,
1421 context_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001422 }
1423
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001424 Scope* saved_scope = scope();
1425 scope_ = stmt->scope();
1426 ASSERT(scope_->declarations()->is_empty());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001427 { WithOrCatch catch_body(this);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001428 Visit(stmt->catch_block());
1429 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001430 // Restore the context.
1431 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1432 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001433 scope_ = saved_scope;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001434 __ jmp(&exit);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001435
1436 // Try block code. Sets up the exception handler chain.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001437 __ bind(&try_entry);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001438 __ PushTryHandler(StackHandler::CATCH, stmt->index());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001439 { TryCatch try_body(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001440 Visit(stmt->try_block());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001441 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001442 __ PopTryHandler();
1443 __ bind(&exit);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001444}
1445
1446
1447void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1448 Comment cmnt(masm_, "[ TryFinallyStatement");
1449 SetStatementPosition(stmt);
1450 // Try finally is compiled by setting up a try-handler on the stack while
1451 // executing the try body, and removing it again afterwards.
1452 //
1453 // The try-finally construct can enter the finally block in three ways:
1454 // 1. By exiting the try-block normally. This removes the try-handler and
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001455 // calls the finally block code before continuing.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001456 // 2. By exiting the try-block with a function-local control flow transfer
1457 // (break/continue/return). The site of the, e.g., break removes the
1458 // try handler and calls the finally block code before continuing
1459 // its outward control transfer.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001460 // 3. By exiting the try-block with a thrown exception.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001461 // This can happen in nested function calls. It traverses the try-handler
1462 // chain and consumes the try-handler entry before jumping to the
1463 // handler code. The handler code then calls the finally-block before
1464 // rethrowing the exception.
1465 //
1466 // The finally block must assume a return address on top of the stack
1467 // (or in the link register on ARM chips) and a value (return value or
1468 // exception) in the result register (rax/eax/r0), both of which must
1469 // be preserved. The return address isn't GC-safe, so it should be
1470 // cooked before GC.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001471 Label try_entry, handler_entry, finally_entry;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001472
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001473 // Jump to try-handler setup and try-block code.
1474 __ jmp(&try_entry);
1475 __ bind(&handler_entry);
1476 handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
1477 // Exception handler code. This code is only executed when an exception
1478 // is thrown. The exception is in the result register, and must be
1479 // preserved by the finally block. Call the finally block and then
1480 // rethrow the exception if it returns.
1481 __ Call(&finally_entry);
danno@chromium.org59400602013-08-13 17:09:37 +00001482 __ Push(result_register());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001483 __ CallRuntime(Runtime::kReThrow, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001484
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001485 // Finally block implementation.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001486 __ bind(&finally_entry);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001487 EnterFinallyBlock();
1488 { Finally finally_body(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001489 Visit(stmt->finally_block());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001490 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001491 ExitFinallyBlock(); // Return to the calling code.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001492
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001493 // Set up try handler.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001494 __ bind(&try_entry);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001495 __ PushTryHandler(StackHandler::FINALLY, stmt->index());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001496 { TryFinally try_body(this, &finally_entry);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001497 Visit(stmt->try_block());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001498 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001499 __ PopTryHandler();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001500 // Execute the finally block on the way out. Clobber the unpredictable
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001501 // value in the result register with one that's safe for GC because the
1502 // finally block will unconditionally preserve the result register on the
1503 // stack.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001504 ClearAccumulator();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001505 __ Call(&finally_entry);
1506}
1507
1508
1509void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1510#ifdef ENABLE_DEBUGGER_SUPPORT
1511 Comment cmnt(masm_, "[ DebuggerStatement");
1512 SetStatementPosition(stmt);
1513
ager@chromium.org5c838252010-02-19 08:53:10 +00001514 __ DebugBreak();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001515 // Ignore the return value.
1516#endif
1517}
1518
1519
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001520void FullCodeGenerator::VisitCaseClause(CaseClause* clause) {
1521 UNREACHABLE();
1522}
1523
1524
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001525void FullCodeGenerator::VisitConditional(Conditional* expr) {
1526 Comment cmnt(masm_, "[ Conditional");
1527 Label true_case, false_case, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001528 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001529
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001530 PrepareForBailoutForId(expr->ThenId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001531 __ bind(&true_case);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001532 SetExpressionPosition(expr->then_expression());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001533 if (context()->IsTest()) {
1534 const TestContext* for_test = TestContext::cast(context());
1535 VisitForControl(expr->then_expression(),
1536 for_test->true_label(),
1537 for_test->false_label(),
1538 NULL);
1539 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001540 VisitInDuplicateContext(expr->then_expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001541 __ jmp(&done);
1542 }
1543
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001544 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001545 __ bind(&false_case);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001546 SetExpressionPosition(expr->else_expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001547 VisitInDuplicateContext(expr->else_expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001548 // If control flow falls through Visit, merge it with true case here.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001549 if (!context()->IsTest()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001550 __ bind(&done);
1551 }
1552}
1553
1554
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001555void FullCodeGenerator::VisitLiteral(Literal* expr) {
1556 Comment cmnt(masm_, "[ Literal");
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001557 context()->Plug(expr->value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001558}
1559
1560
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001561void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1562 Comment cmnt(masm_, "[ FunctionLiteral");
1563
1564 // Build the function boilerplate and instantiate it.
1565 Handle<SharedFunctionInfo> function_info =
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001566 Compiler::BuildFunctionInfo(expr, script());
1567 if (function_info.is_null()) {
1568 SetStackOverflow();
1569 return;
1570 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001571 EmitNewClosure(function_info, expr->pretenure());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001572}
1573
1574
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001575void FullCodeGenerator::VisitNativeFunctionLiteral(
1576 NativeFunctionLiteral* expr) {
1577 Comment cmnt(masm_, "[ NativeFunctionLiteral");
1578
1579 // Compute the function template for the native function.
1580 Handle<String> name = expr->name();
1581 v8::Handle<v8::FunctionTemplate> fun_template =
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001582 expr->extension()->GetNativeFunctionTemplate(
1583 reinterpret_cast<v8::Isolate*>(isolate()), v8::Utils::ToLocal(name));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001584 ASSERT(!fun_template.IsEmpty());
1585
1586 // Instantiate the function and create a shared function info from it.
1587 Handle<JSFunction> fun = Utils::OpenHandle(*fun_template->GetFunction());
1588 const int literals = fun->NumberOfLiterals();
1589 Handle<Code> code = Handle<Code>(fun->shared()->code());
1590 Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
1591 bool is_generator = false;
1592 Handle<SharedFunctionInfo> shared =
1593 isolate()->factory()->NewSharedFunctionInfo(name, literals, is_generator,
1594 code, Handle<ScopeInfo>(fun->shared()->scope_info()));
1595 shared->set_construct_stub(*construct_stub);
1596
1597 // Copy the function data to the shared function info.
1598 shared->set_function_data(fun->shared()->function_data());
1599 int parameters = fun->shared()->formal_parameter_count();
1600 shared->set_formal_parameter_count(parameters);
1601
1602 EmitNewClosure(shared, false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001603}
1604
1605
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001606void FullCodeGenerator::VisitThrow(Throw* expr) {
1607 Comment cmnt(masm_, "[ Throw");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001608 VisitForStackValue(expr->exception());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001609 __ CallRuntime(Runtime::kThrow, 1);
1610 // Never returns here.
1611}
1612
1613
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001614FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit(
1615 int* stack_depth,
1616 int* context_length) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001617 // The macros used here must preserve the result register.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001618 __ Drop(*stack_depth);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001619 __ PopTryHandler();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001620 *stack_depth = 0;
1621 return previous_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001622}
1623
ricow@chromium.org65fae842010-08-25 15:26:24 +00001624
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001625bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001626 Expression* sub_expr;
ager@chromium.org04921a82011-06-27 13:21:41 +00001627 Handle<String> check;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001628 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001629 EmitLiteralCompareTypeof(expr, sub_expr, check);
ager@chromium.org04921a82011-06-27 13:21:41 +00001630 return true;
1631 }
1632
jkummerow@chromium.org96a3c512013-07-18 17:02:47 +00001633 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001634 EmitLiteralCompareNil(expr, sub_expr, kUndefinedValue);
1635 return true;
1636 }
1637
1638 if (expr->IsLiteralCompareNull(&sub_expr)) {
1639 EmitLiteralCompareNil(expr, sub_expr, kNullValue);
ager@chromium.org04921a82011-06-27 13:21:41 +00001640 return true;
1641 }
1642
1643 return false;
1644}
1645
1646
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001647void BackEdgeTable::Patch(Isolate* isolate,
1648 Code* unoptimized) {
1649 DisallowHeapAllocation no_gc;
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001650 Code* patch = isolate->builtins()->builtin(Builtins::kOnStackReplacement);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001651
1652 // Iterate over the back edge table and patch every interrupt
1653 // call to an unconditional call to the replacement code.
1654 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level();
1655
1656 BackEdgeTable back_edges(unoptimized, &no_gc);
1657 for (uint32_t i = 0; i < back_edges.length(); i++) {
1658 if (static_cast<int>(back_edges.loop_depth(i)) == loop_nesting_level) {
1659 ASSERT_EQ(INTERRUPT, GetBackEdgeState(isolate,
1660 unoptimized,
1661 back_edges.pc(i)));
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001662 PatchAt(unoptimized, back_edges.pc(i), ON_STACK_REPLACEMENT, patch);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001663 }
1664 }
1665
1666 unoptimized->set_back_edges_patched_for_osr(true);
1667 ASSERT(Verify(isolate, unoptimized, loop_nesting_level));
1668}
1669
1670
1671void BackEdgeTable::Revert(Isolate* isolate,
1672 Code* unoptimized) {
1673 DisallowHeapAllocation no_gc;
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001674 Code* patch = isolate->builtins()->builtin(Builtins::kInterruptCheck);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001675
1676 // Iterate over the back edge table and revert the patched interrupt calls.
1677 ASSERT(unoptimized->back_edges_patched_for_osr());
1678 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level();
1679
1680 BackEdgeTable back_edges(unoptimized, &no_gc);
1681 for (uint32_t i = 0; i < back_edges.length(); i++) {
1682 if (static_cast<int>(back_edges.loop_depth(i)) <= loop_nesting_level) {
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001683 ASSERT_NE(INTERRUPT, GetBackEdgeState(isolate,
1684 unoptimized,
1685 back_edges.pc(i)));
1686 PatchAt(unoptimized, back_edges.pc(i), INTERRUPT, patch);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001687 }
1688 }
1689
1690 unoptimized->set_back_edges_patched_for_osr(false);
1691 unoptimized->set_allow_osr_at_loop_nesting_level(0);
1692 // Assert that none of the back edges are patched anymore.
1693 ASSERT(Verify(isolate, unoptimized, -1));
1694}
1695
1696
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001697void BackEdgeTable::AddStackCheck(CompilationInfo* info) {
1698 DisallowHeapAllocation no_gc;
1699 Isolate* isolate = info->isolate();
1700 Code* code = info->shared_info()->code();
1701 Address pc = code->instruction_start() + info->osr_pc_offset();
1702 ASSERT_EQ(ON_STACK_REPLACEMENT, GetBackEdgeState(isolate, code, pc));
1703 Code* patch = isolate->builtins()->builtin(Builtins::kOsrAfterStackCheck);
1704 PatchAt(code, pc, OSR_AFTER_STACK_CHECK, patch);
1705}
1706
1707
1708void BackEdgeTable::RemoveStackCheck(CompilationInfo* info) {
1709 DisallowHeapAllocation no_gc;
1710 Isolate* isolate = info->isolate();
1711 Code* code = info->shared_info()->code();
1712 Address pc = code->instruction_start() + info->osr_pc_offset();
1713 if (GetBackEdgeState(isolate, code, pc) == OSR_AFTER_STACK_CHECK) {
1714 Code* patch = isolate->builtins()->builtin(Builtins::kOnStackReplacement);
1715 PatchAt(code, pc, ON_STACK_REPLACEMENT, patch);
1716 }
1717}
1718
1719
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001720#ifdef DEBUG
1721bool BackEdgeTable::Verify(Isolate* isolate,
1722 Code* unoptimized,
1723 int loop_nesting_level) {
1724 DisallowHeapAllocation no_gc;
1725 BackEdgeTable back_edges(unoptimized, &no_gc);
1726 for (uint32_t i = 0; i < back_edges.length(); i++) {
1727 uint32_t loop_depth = back_edges.loop_depth(i);
1728 CHECK_LE(static_cast<int>(loop_depth), Code::kMaxLoopNestingMarker);
1729 // Assert that all back edges for shallower loops (and only those)
1730 // have already been patched.
1731 CHECK_EQ((static_cast<int>(loop_depth) <= loop_nesting_level),
1732 GetBackEdgeState(isolate,
1733 unoptimized,
1734 back_edges.pc(i)) != INTERRUPT);
1735 }
1736 return true;
1737}
1738#endif // DEBUG
1739
1740
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001741#undef __
1742
1743
1744} } // namespace v8::internal