blob: fd4079cb4ff8a5f7b6db581842eee4711b0f62dd [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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_IA32
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000032#include "code-stubs.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000034#include "compiler.h"
35#include "debug.h"
36#include "full-codegen.h"
danno@chromium.org88aa0582012-03-23 15:11:57 +000037#include "isolate-inl.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000038#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000039#include "scopes.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000040#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000041
42namespace v8 {
43namespace internal {
44
45#define __ ACCESS_MASM(masm_)
46
danno@chromium.org40cb8782011-05-25 07:58:50 +000047
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000048class JumpPatchSite BASE_EMBEDDED {
49 public:
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000050 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000051#ifdef DEBUG
52 info_emitted_ = false;
53#endif
54 }
55
56 ~JumpPatchSite() {
57 ASSERT(patch_site_.is_bound() == info_emitted_);
58 }
59
karlklose@chromium.org83a47282011-05-11 11:54:09 +000060 void EmitJumpIfNotSmi(Register reg,
61 Label* target,
62 Label::Distance distance = Label::kFar) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000063 __ test(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000064 EmitJump(not_carry, target, distance); // Always taken before patched.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000065 }
66
karlklose@chromium.org83a47282011-05-11 11:54:09 +000067 void EmitJumpIfSmi(Register reg,
68 Label* target,
69 Label::Distance distance = Label::kFar) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000070 __ test(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000071 EmitJump(carry, target, distance); // Never taken before patched.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000072 }
73
74 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000075 if (patch_site_.is_bound()) {
76 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
77 ASSERT(is_int8(delta_to_patch_site));
78 __ test(eax, Immediate(delta_to_patch_site));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000079#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +000080 info_emitted_ = true;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000081#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +000082 } else {
83 __ nop(); // Signals no inlined code.
84 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000085 }
86
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000087 private:
88 // jc will be patched with jz, jnc will become jnz.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000089 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000090 ASSERT(!patch_site_.is_bound() && !info_emitted_);
91 ASSERT(cc == carry || cc == not_carry);
92 __ bind(&patch_site_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +000093 __ j(cc, target, distance);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000094 }
95
96 MacroAssembler* masm_;
97 Label patch_site_;
98#ifdef DEBUG
99 bool info_emitted_;
100#endif
101};
102
103
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000104// Generate code for a JS function. On entry to the function the receiver
105// and arguments have been pushed on the stack left to right, with the
106// return address on top of them. The actual argument count matches the
107// formal parameter count expected by the function.
108//
109// The live registers are:
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000110// o edi: the JS function object being called (i.e. ourselves)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000111// o esi: our context
112// o ebp: our caller's frame pointer
113// o esp: stack pointer (pointing to return address)
114//
115// The function builds a JS frame. Please see JavaScriptFrameConstants in
116// frames-ia32.h for its layout.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000117void FullCodeGenerator::Generate() {
118 CompilationInfo* info = info_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000119 handler_table_ =
120 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
machenbach@chromium.org7d6bc7d2014-02-11 08:13:48 +0000121
122 InitializeFeedbackVector();
123
danno@chromium.org41728482013-06-12 22:31:22 +0000124 profiling_counter_ = isolate()->factory()->NewCell(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000125 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000126 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000127 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000129 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
130
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000131#ifdef DEBUG
132 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000133 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000134 __ int3();
135 }
136#endif
137
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000138 // Classic mode functions and builtins need to replace the receiver with the
139 // global proxy when called as functions (without an explicit receiver
140 // object).
141 if (info->is_classic_mode() && !info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000142 Label ok;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000143 // +1 for return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000144 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000145 __ mov(ecx, Operand(esp, receiver_offset));
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000146
147 __ cmp(ecx, isolate()->factory()->undefined_value());
danno@chromium.orgc612e022011-11-10 11:38:15 +0000148 __ j(not_equal, &ok, Label::kNear);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000149
150 __ mov(ecx, GlobalObjectOperand());
151 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
152
153 __ mov(Operand(esp, receiver_offset), ecx);
154
danno@chromium.org40cb8782011-05-25 07:58:50 +0000155 __ bind(&ok);
156 }
157
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000158 // Open a frame scope to indicate that there is a frame on the stack. The
159 // MANUAL indicates that the scope shouldn't actually generate code to set up
160 // the frame (that is done below).
161 FrameScope frame_scope(masm_, StackFrame::MANUAL);
162
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000163 info->set_prologue_offset(masm_->pc_offset());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000164 __ Prologue(BUILD_FUNCTION_FRAME);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000165 info->AddNoFrameRange(0, masm_->pc_offset());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000166
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000167 { Comment cmnt(masm_, "[ Allocate locals");
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000168 int locals_count = info->scope()->num_stack_slots();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000169 // Generators allocate locals, if any, in context slots.
170 ASSERT(!info->function()->is_generator() || locals_count == 0);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000171 if (locals_count == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000172 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000173 } else if (locals_count > 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000174 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000175 for (int i = 0; i < locals_count; i++) {
176 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 }
178 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000179 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000180
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000181 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000182
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000183 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000184 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000185 if (heap_slots > 0) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000186 Comment cmnt(masm_, "[ Allocate context");
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000187 // Argument to NewContext is the function, which is still in edi.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000188 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000189 __ push(edi);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000190 __ Push(info->scope()->GetScopeInfo());
191 __ CallRuntime(Runtime::kNewGlobalContext, 2);
192 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000193 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000195 } else {
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000196 __ push(edi);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000197 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000198 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000199 function_in_register = false;
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000200 // Context is returned in eax. It replaces the context passed to us.
201 // It's saved in the stack and kept live in esi.
202 __ mov(esi, eax);
203 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000204
205 // Copy parameters into context if necessary.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000206 int num_parameters = info->scope()->num_parameters();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000207 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000208 Variable* var = scope()->parameter(i);
209 if (var->IsContextSlot()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000210 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
211 (num_parameters - 1 - i) * kPointerSize;
212 // Load parameter from stack.
213 __ mov(eax, Operand(ebp, parameter_offset));
214 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000215 int context_offset = Context::SlotOffset(var->index());
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000216 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000217 // Update the write barrier. This clobbers eax and ebx.
218 __ RecordWriteContextSlot(esi,
219 context_offset,
220 eax,
221 ebx,
222 kDontSaveFPRegs);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000223 }
224 }
225 }
226
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000227 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000228 if (arguments != NULL) {
229 // Function uses arguments object.
230 Comment cmnt(masm_, "[ Allocate arguments object");
231 if (function_in_register) {
232 __ push(edi);
233 } else {
234 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
235 }
236 // Receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000237 int num_parameters = info->scope()->num_parameters();
238 int offset = num_parameters * kPointerSize;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000239 __ lea(edx,
240 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
241 __ push(edx);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000242 __ push(Immediate(Smi::FromInt(num_parameters)));
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000243 // Arguments to ArgumentsAccessStub:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000244 // function, receiver address, parameter count.
245 // The stub will rewrite receiver and parameter count if the previous
246 // stack frame was an arguments adapter frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000247 ArgumentsAccessStub::Type type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000248 if (!is_classic_mode()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +0000249 type = ArgumentsAccessStub::NEW_STRICT;
250 } else if (function()->has_duplicate_parameters()) {
251 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
252 } else {
253 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
254 }
255 ArgumentsAccessStub stub(type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000256 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000257
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000258 SetVar(arguments, eax, ebx, edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000259 }
260
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000261 if (FLAG_trace) {
262 __ CallRuntime(Runtime::kTraceEnter, 0);
263 }
264
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000265 // Visit the declarations and body unless there is an illegal
266 // redeclaration.
267 if (scope()->HasIllegalRedeclaration()) {
268 Comment cmnt(masm_, "[ Declarations");
269 scope()->VisitIllegalRedeclaration(this);
270
271 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000272 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000273 { Comment cmnt(masm_, "[ Declarations");
274 // For named function expressions, declare the function name as a
275 // constant.
276 if (scope()->is_function_scope() && scope()->function() != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000277 VariableDeclaration* function = scope()->function();
278 ASSERT(function->proxy()->var()->mode() == CONST ||
279 function->proxy()->var()->mode() == CONST_HARMONY);
280 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
281 VisitVariableDeclaration(function);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000282 }
283 VisitDeclarations(scope()->declarations());
284 }
285
286 { Comment cmnt(masm_, "[ Stack check");
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000287 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000288 Label ok;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000289 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290 ExternalReference::address_of_stack_limit(isolate());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000291 __ cmp(esp, Operand::StaticVariable(stack_limit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000292 __ j(above_equal, &ok, Label::kNear);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000293 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000294 __ bind(&ok);
295 }
296
297 { Comment cmnt(masm_, "[ Body");
298 ASSERT(loop_depth() == 0);
299 VisitStatements(function()->body());
300 ASSERT(loop_depth() == 0);
301 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000302 }
303
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000304 // Always emit a 'return undefined' in case control fell off the end of
305 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000306 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000307 __ mov(eax, isolate()->factory()->undefined_value());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000308 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000309 }
310}
311
312
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000313void FullCodeGenerator::ClearAccumulator() {
314 __ Set(eax, Immediate(Smi::FromInt(0)));
315}
316
317
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000318void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
319 __ mov(ebx, Immediate(profiling_counter_));
danno@chromium.org41728482013-06-12 22:31:22 +0000320 __ sub(FieldOperand(ebx, Cell::kValueOffset),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000321 Immediate(Smi::FromInt(delta)));
322}
323
324
325void FullCodeGenerator::EmitProfilingCounterReset() {
326 int reset_value = FLAG_interrupt_budget;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000327 __ mov(ebx, Immediate(profiling_counter_));
danno@chromium.org41728482013-06-12 22:31:22 +0000328 __ mov(FieldOperand(ebx, Cell::kValueOffset),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000329 Immediate(Smi::FromInt(reset_value)));
330}
331
332
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000333void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
334 Label* back_edge_target) {
335 Comment cmnt(masm_, "[ Back edge bookkeeping");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000336 Label ok;
yangguo@chromium.org56454712012-02-16 15:33:53 +0000337
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000338 ASSERT(back_edge_target->is_bound());
339 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
340 int weight = Min(kMaxBackEdgeWeight,
341 Max(1, distance / kCodeSizeMultiplier));
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000342 EmitProfilingCounterDecrement(weight);
343 __ j(positive, &ok, Label::kNear);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000344 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +0000345
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000346 // Record a mapping of this PC offset to the OSR id. This is used to find
347 // the AST id from the unoptimized code in order to use it as a key into
348 // the deoptimization input data found in the optimized code.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000349 RecordBackEdge(stmt->OsrEntryId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000350
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000351 EmitProfilingCounterReset();
yangguo@chromium.org56454712012-02-16 15:33:53 +0000352
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000353 __ bind(&ok);
354 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
355 // Record a mapping of the OSR id to this PC. This is used if the OSR
356 // entry becomes the target of a bailout. We don't expect it to be, but
357 // we want it to work if it is.
358 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000359}
360
361
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000362void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000363 Comment cmnt(masm_, "[ Return sequence");
364 if (return_label_.is_bound()) {
365 __ jmp(&return_label_);
366 } else {
367 // Common return label
368 __ bind(&return_label_);
369 if (FLAG_trace) {
370 __ push(eax);
371 __ CallRuntime(Runtime::kTraceExit, 1);
372 }
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000373 // Pretend that the exit is a backwards jump to the entry.
374 int weight = 1;
375 if (info_->ShouldSelfOptimize()) {
376 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
377 } else {
378 int distance = masm_->pc_offset();
379 weight = Min(kMaxBackEdgeWeight,
380 Max(1, distance / kCodeSizeMultiplier));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000381 }
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000382 EmitProfilingCounterDecrement(weight);
383 Label ok;
384 __ j(positive, &ok, Label::kNear);
385 __ push(eax);
386 __ call(isolate()->builtins()->InterruptCheck(),
387 RelocInfo::CODE_TARGET);
388 __ pop(eax);
389 EmitProfilingCounterReset();
390 __ bind(&ok);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000391#ifdef DEBUG
392 // Add a label for checking the size of the code used for returning.
393 Label check_exit_codesize;
394 masm_->bind(&check_exit_codesize);
395#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000396 SetSourcePosition(function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000397 __ RecordJSReturn();
398 // Do not use the leave instruction here because it is too short to
399 // patch with the code required by the debugger.
400 __ mov(esp, ebp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000401 int no_frame_start = masm_->pc_offset();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000402 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000403
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000404 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000405 __ Ret(arguments_bytes, ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000406#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000407 // Check that the size of the code used for returning is large enough
408 // for the debugger's requirements.
409 ASSERT(Assembler::kJSReturnSequenceLength <=
410 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000411#endif
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000412 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000413 }
414}
415
416
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000417void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
418 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000419}
420
421
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000422void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
423 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
424 codegen()->GetVar(result_register(), var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000425}
426
427
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000428void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
429 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
430 MemOperand operand = codegen()->VarOperand(var, result_register());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000431 // Memory operands can be pushed directly.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000432 __ push(operand);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000433}
434
435
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000436void FullCodeGenerator::TestContext::Plug(Variable* var) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000437 // For simplicity we always test the accumulator register.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000438 codegen()->GetVar(result_register(), var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000439 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000440 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000441}
442
443
444void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
445 UNREACHABLE(); // Not used on IA32.
446}
447
448
449void FullCodeGenerator::AccumulatorValueContext::Plug(
450 Heap::RootListIndex index) const {
451 UNREACHABLE(); // Not used on IA32.
452}
453
454
455void FullCodeGenerator::StackValueContext::Plug(
456 Heap::RootListIndex index) const {
457 UNREACHABLE(); // Not used on IA32.
458}
459
460
461void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
462 UNREACHABLE(); // Not used on IA32.
463}
464
465
466void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
467}
468
469
470void FullCodeGenerator::AccumulatorValueContext::Plug(
471 Handle<Object> lit) const {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000472 if (lit->IsSmi()) {
473 __ SafeSet(result_register(), Immediate(lit));
474 } else {
475 __ Set(result_register(), Immediate(lit));
476 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000477}
478
479
480void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000481 if (lit->IsSmi()) {
482 __ SafePush(Immediate(lit));
483 } else {
484 __ push(Immediate(lit));
485 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000486}
487
488
489void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000490 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000491 true,
492 true_label_,
493 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000494 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
495 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000496 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000497 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000498 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000499 } else if (lit->IsString()) {
500 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000501 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000502 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000503 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000504 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000505 } else if (lit->IsSmi()) {
506 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000507 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000508 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000509 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000510 }
511 } else {
512 // For simplicity we always test the accumulator register.
513 __ mov(result_register(), lit);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000514 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000515 }
516}
517
518
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000519void FullCodeGenerator::EffectContext::DropAndPlug(int count,
520 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000521 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000522 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000523}
524
525
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000526void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
527 int count,
528 Register reg) const {
529 ASSERT(count > 0);
530 __ Drop(count);
531 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000532}
533
534
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000535void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
536 Register reg) const {
537 ASSERT(count > 0);
538 if (count > 1) __ Drop(count - 1);
539 __ mov(Operand(esp, 0), reg);
540}
541
542
543void FullCodeGenerator::TestContext::DropAndPlug(int count,
544 Register reg) const {
545 ASSERT(count > 0);
546 // For simplicity we always test the accumulator register.
547 __ Drop(count);
548 __ Move(result_register(), reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000549 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000550 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000551}
552
553
554void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
555 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000556 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000557 __ bind(materialize_true);
558}
559
560
561void FullCodeGenerator::AccumulatorValueContext::Plug(
562 Label* materialize_true,
563 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000564 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000565 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 __ mov(result_register(), isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000567 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000568 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 __ mov(result_register(), isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000570 __ bind(&done);
571}
572
573
574void FullCodeGenerator::StackValueContext::Plug(
575 Label* materialize_true,
576 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000577 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000578 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 __ push(Immediate(isolate()->factory()->true_value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000580 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000581 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 __ push(Immediate(isolate()->factory()->false_value()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000583 __ bind(&done);
584}
585
586
587void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
588 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000589 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000590 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000591}
592
593
594void FullCodeGenerator::EffectContext::Plug(bool flag) const {
595}
596
597
598void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 Handle<Object> value = flag
600 ? isolate()->factory()->true_value()
601 : isolate()->factory()->false_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000602 __ mov(result_register(), value);
603}
604
605
606void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> value = flag
608 ? isolate()->factory()->true_value()
609 : isolate()->factory()->false_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000610 __ push(Immediate(value));
611}
612
613
614void FullCodeGenerator::TestContext::Plug(bool flag) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000615 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000616 true,
617 true_label_,
618 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000619 if (flag) {
620 if (true_label_ != fall_through_) __ jmp(true_label_);
621 } else {
622 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000623 }
624}
625
626
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000627void FullCodeGenerator::DoTest(Expression* condition,
628 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000629 Label* if_false,
630 Label* fall_through) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000631 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +0000632 CallIC(ic, condition->test_id());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 __ test(result_register(), result_register());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000634 // The stub returns nonzero for true.
635 Split(not_zero, if_true, if_false, fall_through);
636}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000637
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000638
ricow@chromium.org65fae842010-08-25 15:26:24 +0000639void FullCodeGenerator::Split(Condition cc,
640 Label* if_true,
641 Label* if_false,
642 Label* fall_through) {
643 if (if_false == fall_through) {
644 __ j(cc, if_true);
645 } else if (if_true == fall_through) {
646 __ j(NegateCondition(cc), if_false);
647 } else {
648 __ j(cc, if_true);
649 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000650 }
651}
652
653
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000654MemOperand FullCodeGenerator::StackOperand(Variable* var) {
655 ASSERT(var->IsStackAllocated());
656 // Offset is negative because higher indexes are at lower addresses.
657 int offset = -var->index() * kPointerSize;
658 // Adjust by a (parameter or local) base offset.
659 if (var->IsParameter()) {
660 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
661 } else {
662 offset += JavaScriptFrameConstants::kLocal0Offset;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000663 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000664 return Operand(ebp, offset);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000665}
666
667
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000668MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
669 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
670 if (var->IsContextSlot()) {
671 int context_chain_length = scope()->ContextChainLength(var->scope());
672 __ LoadContext(scratch, context_chain_length);
673 return ContextOperand(scratch, var->index());
674 } else {
675 return StackOperand(var);
676 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000677}
678
679
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000680void FullCodeGenerator::GetVar(Register dest, Variable* var) {
681 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
682 MemOperand location = VarOperand(var, dest);
683 __ mov(dest, location);
684}
685
686
687void FullCodeGenerator::SetVar(Variable* var,
688 Register src,
689 Register scratch0,
690 Register scratch1) {
691 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
692 ASSERT(!scratch0.is(src));
693 ASSERT(!scratch0.is(scratch1));
694 ASSERT(!scratch1.is(src));
695 MemOperand location = VarOperand(var, scratch0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000696 __ mov(location, src);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000697
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000698 // Emit the write barrier code if the location is in the heap.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000699 if (var->IsContextSlot()) {
700 int offset = Context::SlotOffset(var->index());
701 ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000702 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000703 }
704}
705
706
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000707void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000708 bool should_normalize,
709 Label* if_true,
710 Label* if_false) {
711 // Only prepare for bailouts before splits if we're in a test
712 // context. Otherwise, we let the Visit function deal with the
713 // preparation to avoid preparing with the same AST id twice.
714 if (!context()->IsTest() || !info_->IsOptimizable()) return;
715
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000716 Label skip;
717 if (should_normalize) __ jmp(&skip, Label::kNear);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000718 PrepareForBailout(expr, TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000719 if (should_normalize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000720 __ cmp(eax, isolate()->factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000721 Split(equal, if_true, if_false, NULL);
722 __ bind(&skip);
723 }
724}
725
726
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000727void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000728 // The variable in the declaration always resides in the current context.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000729 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000730 if (generate_debug_code_) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000731 // Check that we're not inside a with or catch context.
732 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
733 __ cmp(ebx, isolate()->factory()->with_context_map());
danno@chromium.org59400602013-08-13 17:09:37 +0000734 __ Check(not_equal, kDeclarationInWithContext);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000735 __ cmp(ebx, isolate()->factory()->catch_context_map());
danno@chromium.org59400602013-08-13 17:09:37 +0000736 __ Check(not_equal, kDeclarationInCatchContext);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000737 }
738}
739
740
741void FullCodeGenerator::VisitVariableDeclaration(
742 VariableDeclaration* declaration) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000743 // If it was not possible to allocate the variable at compile time, we
744 // need to "declare" it at runtime to make sure it actually exists in the
745 // local context.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000746 VariableProxy* proxy = declaration->proxy();
747 VariableMode mode = declaration->mode();
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000748 Variable* variable = proxy->var();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000749 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000750 switch (variable->location()) {
751 case Variable::UNALLOCATED:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000752 globals_->Add(variable->name(), zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000753 globals_->Add(variable->binding_needs_init()
754 ? isolate()->factory()->the_hole_value()
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000755 : isolate()->factory()->undefined_value(), zone());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000756 break;
757
758 case Variable::PARAMETER:
759 case Variable::LOCAL:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000760 if (hole_init) {
761 Comment cmnt(masm_, "[ VariableDeclaration");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000762 __ mov(StackOperand(variable),
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000763 Immediate(isolate()->factory()->the_hole_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000764 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000765 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000766
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000767 case Variable::CONTEXT:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000768 if (hole_init) {
769 Comment cmnt(masm_, "[ VariableDeclaration");
770 EmitDebugCheckDeclarationContext(variable);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000771 __ mov(ContextOperand(esi, variable->index()),
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000772 Immediate(isolate()->factory()->the_hole_value()));
773 // No write barrier since the hole value is in old space.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000774 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000775 }
776 break;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000777
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000778 case Variable::LOOKUP: {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000779 Comment cmnt(masm_, "[ VariableDeclaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000780 __ push(esi);
781 __ push(Immediate(variable->name()));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000782 // VariableDeclaration nodes are always introduced in one of four modes.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000783 ASSERT(IsDeclaredVariableMode(mode));
784 PropertyAttributes attr =
785 IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000786 __ push(Immediate(Smi::FromInt(attr)));
787 // Push initial value, if any.
788 // Note: For variables we must not push an initial value (such as
789 // 'undefined') because we may have a (legal) redeclaration and we
790 // must not destroy the current value.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000791 if (hole_init) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000792 __ push(Immediate(isolate()->factory()->the_hole_value()));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000793 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000794 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000795 }
796 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000797 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000798 }
799 }
800}
801
802
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000803void FullCodeGenerator::VisitFunctionDeclaration(
804 FunctionDeclaration* declaration) {
805 VariableProxy* proxy = declaration->proxy();
806 Variable* variable = proxy->var();
807 switch (variable->location()) {
808 case Variable::UNALLOCATED: {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000809 globals_->Add(variable->name(), zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000810 Handle<SharedFunctionInfo> function =
811 Compiler::BuildFunctionInfo(declaration->fun(), script());
812 // Check for stack-overflow exception.
813 if (function.is_null()) return SetStackOverflow();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000814 globals_->Add(function, zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000815 break;
816 }
817
818 case Variable::PARAMETER:
819 case Variable::LOCAL: {
820 Comment cmnt(masm_, "[ FunctionDeclaration");
821 VisitForAccumulatorValue(declaration->fun());
822 __ mov(StackOperand(variable), result_register());
823 break;
824 }
825
826 case Variable::CONTEXT: {
827 Comment cmnt(masm_, "[ FunctionDeclaration");
828 EmitDebugCheckDeclarationContext(variable);
829 VisitForAccumulatorValue(declaration->fun());
830 __ mov(ContextOperand(esi, variable->index()), result_register());
831 // We know that we have written a function, which is not a smi.
832 __ RecordWriteContextSlot(esi,
833 Context::SlotOffset(variable->index()),
834 result_register(),
835 ecx,
836 kDontSaveFPRegs,
837 EMIT_REMEMBERED_SET,
838 OMIT_SMI_CHECK);
839 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
840 break;
841 }
842
843 case Variable::LOOKUP: {
844 Comment cmnt(masm_, "[ FunctionDeclaration");
845 __ push(esi);
846 __ push(Immediate(variable->name()));
847 __ push(Immediate(Smi::FromInt(NONE)));
848 VisitForStackValue(declaration->fun());
849 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
850 break;
851 }
852 }
853}
854
855
856void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000857 Variable* variable = declaration->proxy()->var();
858 ASSERT(variable->location() == Variable::CONTEXT);
859 ASSERT(variable->interface()->IsFrozen());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000860
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000861 Comment cmnt(masm_, "[ ModuleDeclaration");
862 EmitDebugCheckDeclarationContext(variable);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000863
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000864 // Load instance object.
865 __ LoadContext(eax, scope_->ContextChainLength(scope_->GlobalScope()));
866 __ mov(eax, ContextOperand(eax, variable->interface()->Index()));
867 __ mov(eax, ContextOperand(eax, Context::EXTENSION_INDEX));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000868
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000869 // Assign it.
870 __ mov(ContextOperand(esi, variable->index()), eax);
871 // We know that we have written a module, which is not a smi.
872 __ RecordWriteContextSlot(esi,
873 Context::SlotOffset(variable->index()),
874 eax,
875 ecx,
876 kDontSaveFPRegs,
877 EMIT_REMEMBERED_SET,
878 OMIT_SMI_CHECK);
879 PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
880
881 // Traverse into body.
882 Visit(declaration->module());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000883}
884
885
886void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
887 VariableProxy* proxy = declaration->proxy();
888 Variable* variable = proxy->var();
889 switch (variable->location()) {
890 case Variable::UNALLOCATED:
891 // TODO(rossberg)
892 break;
893
894 case Variable::CONTEXT: {
895 Comment cmnt(masm_, "[ ImportDeclaration");
896 EmitDebugCheckDeclarationContext(variable);
897 // TODO(rossberg)
898 break;
899 }
900
901 case Variable::PARAMETER:
902 case Variable::LOCAL:
903 case Variable::LOOKUP:
904 UNREACHABLE();
905 }
906}
907
908
909void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
910 // TODO(rossberg)
911}
912
913
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000914void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
915 // Call the runtime to declare the globals.
916 __ push(esi); // The context is the first argument.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000917 __ Push(pairs);
918 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000919 __ CallRuntime(Runtime::kDeclareGlobals, 3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000920 // Return value is ignored.
921}
922
923
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000924void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
925 // Call the runtime to declare the modules.
926 __ Push(descriptions);
927 __ CallRuntime(Runtime::kDeclareModules, 1);
928 // Return value is ignored.
929}
930
931
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000932void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
933 Comment cmnt(masm_, "[ SwitchStatement");
934 Breakable nested_statement(this, stmt);
935 SetStatementPosition(stmt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000936
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000937 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000938 VisitForStackValue(stmt->tag());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000939 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000940
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000941 ZoneList<CaseClause*>* clauses = stmt->cases();
942 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000943
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000944 Label next_test; // Recycled for each test.
945 // Compile all the tests with branches to their bodies.
946 for (int i = 0; i < clauses->length(); i++) {
947 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000948 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000949
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000950 // The default is not a test, but remember it as final fall through.
951 if (clause->is_default()) {
952 default_clause = clause;
953 continue;
954 }
955
956 Comment cmnt(masm_, "[ Case comparison");
957 __ bind(&next_test);
958 next_test.Unuse();
959
960 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000961 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000962
ricow@chromium.org65fae842010-08-25 15:26:24 +0000963 // Perform the comparison as if via '==='.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000964 __ mov(edx, Operand(esp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000965 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000966 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000967 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000968 Label slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000969 __ mov(ecx, edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000970 __ or_(ecx, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000971 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000972
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000973 __ cmp(edx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000974 __ j(not_equal, &next_test);
975 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000976 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000977 __ bind(&slow_case);
978 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000979
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000980 // Record position before stub call for type feedback.
981 SetSourcePosition(clause->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000982 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT);
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +0000983 CallIC(ic, clause->CompareId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000984 patch_site.EmitPatchInfo();
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000985
986 Label skip;
987 __ jmp(&skip, Label::kNear);
988 PrepareForBailout(clause, TOS_REG);
989 __ cmp(eax, isolate()->factory()->true_value());
990 __ j(not_equal, &next_test);
991 __ Drop(1);
992 __ jmp(clause->body_target());
993 __ bind(&skip);
994
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000995 __ test(eax, eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000996 __ j(not_equal, &next_test);
997 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000998 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000999 }
1000
1001 // Discard the test value and jump to the default if present, otherwise to
1002 // the end of the statement.
1003 __ bind(&next_test);
1004 __ Drop(1); // Switch value is no longer needed.
1005 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001006 __ jmp(nested_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001007 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001008 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001009 }
1010
1011 // Compile all the case bodies.
1012 for (int i = 0; i < clauses->length(); i++) {
1013 Comment cmnt(masm_, "[ Case body");
1014 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001015 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001016 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001017 VisitStatements(clause->statements());
1018 }
1019
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001020 __ bind(nested_statement.break_label());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001021 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001022}
1023
1024
1025void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1026 Comment cmnt(masm_, "[ ForInStatement");
machenbach@chromium.org7d6bc7d2014-02-11 08:13:48 +00001027 int slot = stmt->ForInFeedbackSlot();
1028
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001029 SetStatementPosition(stmt);
1030
1031 Label loop, exit;
1032 ForIn loop_statement(this, stmt);
1033 increment_loop_depth();
1034
danno@chromium.org1fd77d52013-06-07 16:01:45 +00001035 // Get the object to enumerate over. If the object is null or undefined, skip
1036 // over the loop. See ECMA-262 version 5, section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001037 VisitForAccumulatorValue(stmt->enumerable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001038 __ cmp(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001039 __ j(equal, &exit);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001040 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001041 __ j(equal, &exit);
1042
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001043 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1044
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001045 // Convert the object to a JS object.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001046 Label convert, done_convert;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001047 __ JumpIfSmi(eax, &convert, Label::kNear);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001048 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001049 __ j(above_equal, &done_convert, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001050 __ bind(&convert);
1051 __ push(eax);
1052 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1053 __ bind(&done_convert);
1054 __ push(eax);
1055
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001056 // Check for proxies.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001057 Label call_runtime, use_cache, fixed_array;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001058 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1059 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
1060 __ j(below_equal, &call_runtime);
1061
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001062 // Check cache validity in generated code. This is a fast case for
1063 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1064 // guarantee cache validity, call the runtime system to check cache
1065 // validity or get the property names in a fixed array.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001066 __ CheckEnumCache(&call_runtime);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001067
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001068 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001069 __ jmp(&use_cache, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001070
1071 // Get the set of properties to enumerate.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001072 __ bind(&call_runtime);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001073 __ push(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001074 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1076 isolate()->factory()->meta_map());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001077 __ j(not_equal, &fixed_array);
1078
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001079
1080 // We got a map in register eax. Get the enumeration cache from it.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001081 Label no_descriptors;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001082 __ bind(&use_cache);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001083
1084 __ EnumLength(edx, eax);
1085 __ cmp(edx, Immediate(Smi::FromInt(0)));
1086 __ j(equal, &no_descriptors);
1087
danno@chromium.org40cb8782011-05-25 07:58:50 +00001088 __ LoadInstanceDescriptors(eax, ecx);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001089 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001090 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001091
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001092 // Set up the four remaining stack slots.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001093 __ push(eax); // Map.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001094 __ push(ecx); // Enumeration cache.
1095 __ push(edx); // Number of valid entries for the map in the enum cache.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001096 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1097 __ jmp(&loop);
1098
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001099 __ bind(&no_descriptors);
1100 __ add(esp, Immediate(kPointerSize));
1101 __ jmp(&exit);
1102
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001103 // We got a fixed array in register eax. Iterate through that.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001104 Label non_proxy;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001105 __ bind(&fixed_array);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001106
machenbach@chromium.org7d6bc7d2014-02-11 08:13:48 +00001107 Handle<Object> feedback = Handle<Object>(
1108 Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker),
1109 isolate());
1110 StoreFeedbackVectorSlot(slot, feedback);
1111
1112 // No need for a write barrier, we are storing a Smi in the feedback vector.
1113 __ LoadHeapObject(ebx, FeedbackVector());
1114 __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)),
1115 Immediate(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)));
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001116
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001117 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
1118 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
1119 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1120 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
1121 __ j(above, &non_proxy);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001122 __ Set(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001123 __ bind(&non_proxy);
1124 __ push(ebx); // Smi
1125 __ push(eax); // Array
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001126 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001127 __ push(eax); // Fixed array length (as smi).
1128 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1129
1130 // Generate code for doing the condition check.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001131 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001132 __ bind(&loop);
1133 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1134 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001135 __ j(above_equal, loop_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001136
1137 // Get the current entry of the array into register ebx.
1138 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1139 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1140
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001141 // Get the expected map from the stack or a smi in the
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001142 // permanent slow case into register edx.
1143 __ mov(edx, Operand(esp, 3 * kPointerSize));
1144
1145 // Check if the expected map still matches that of the enumerable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001146 // If not, we may have to filter the key.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001147 Label update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001148 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1149 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001150 __ j(equal, &update_each, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001151
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001152 // For proxies, no filtering is done.
1153 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1154 ASSERT(Smi::FromInt(0) == 0);
1155 __ test(edx, edx);
1156 __ j(zero, &update_each);
1157
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001158 // Convert the entry to a string or null if it isn't a property
1159 // anymore. If the property has been removed while iterating, we
1160 // just skip it.
1161 __ push(ecx); // Enumerable.
1162 __ push(ebx); // Current entry.
1163 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001164 __ test(eax, eax);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001165 __ j(equal, loop_statement.continue_label());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001166 __ mov(ebx, eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001167
1168 // Update the 'each' property or variable from the possibly filtered
1169 // entry in register ebx.
1170 __ bind(&update_each);
1171 __ mov(result_register(), ebx);
1172 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001173 { EffectContext context(this);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001174 EmitAssignment(stmt->each());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001175 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001176
1177 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001178 Visit(stmt->body());
1179
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001180 // Generate code for going to the next element by incrementing the
1181 // index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001182 __ bind(loop_statement.continue_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001183 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001184
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001185 EmitBackEdgeBookkeeping(stmt, &loop);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001186 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001187
1188 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001189 __ bind(loop_statement.break_label());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001190 __ add(esp, Immediate(5 * kPointerSize));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001191
1192 // Exit and decrement the loop depth.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001193 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001194 __ bind(&exit);
1195 decrement_loop_depth();
1196}
1197
1198
danno@chromium.org1fd77d52013-06-07 16:01:45 +00001199void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1200 Comment cmnt(masm_, "[ ForOfStatement");
1201 SetStatementPosition(stmt);
1202
1203 Iteration loop_statement(this, stmt);
1204 increment_loop_depth();
1205
1206 // var iterator = iterable[@@iterator]()
1207 VisitForAccumulatorValue(stmt->assign_iterator());
1208
1209 // As with for-in, skip the loop if the iterator is null or undefined.
1210 __ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
1211 __ j(equal, loop_statement.break_label());
1212 __ CompareRoot(eax, Heap::kNullValueRootIndex);
1213 __ j(equal, loop_statement.break_label());
1214
1215 // Convert the iterator to a JS object.
1216 Label convert, done_convert;
1217 __ JumpIfSmi(eax, &convert);
1218 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
1219 __ j(above_equal, &done_convert);
1220 __ bind(&convert);
1221 __ push(eax);
1222 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1223 __ bind(&done_convert);
1224
1225 // Loop entry.
1226 __ bind(loop_statement.continue_label());
1227
1228 // result = iterator.next()
1229 VisitForEffect(stmt->next_result());
1230
1231 // if (result.done) break;
1232 Label result_not_done;
1233 VisitForControl(stmt->result_done(),
1234 loop_statement.break_label(),
1235 &result_not_done,
1236 &result_not_done);
1237 __ bind(&result_not_done);
1238
1239 // each = result.value
1240 VisitForEffect(stmt->assign_each());
1241
1242 // Generate code for the body of the loop.
1243 Visit(stmt->body());
1244
1245 // Check stack before looping.
1246 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
1247 EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
1248 __ jmp(loop_statement.continue_label());
1249
1250 // Exit and decrement the loop depth.
1251 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1252 __ bind(loop_statement.break_label());
1253 decrement_loop_depth();
1254}
1255
1256
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001257void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1258 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001259 // Use the fast case closure allocation code that allocates in new
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001260 // space for nested functions that don't need literals cloning. If
1261 // we're running with the --always-opt or the --prepare-always-opt
1262 // flag, we need to use the runtime function so that the new function
1263 // we are creating here gets a chance to have its code optimized and
1264 // doesn't just get a copy of the existing unoptimized code.
1265 if (!FLAG_always_opt &&
1266 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 !pretenure &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001268 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 info->num_literals() == 0) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001270 FastNewClosureStub stub(info->language_mode(), info->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001271 __ mov(ebx, Immediate(info));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001272 __ CallStub(&stub);
1273 } else {
1274 __ push(esi);
1275 __ push(Immediate(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001276 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 ? isolate()->factory()->true_value()
1278 : isolate()->factory()->false_value()));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001279 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001280 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001281 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001282}
1283
1284
1285void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1286 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001287 EmitVariableLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001288}
1289
1290
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001291void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1292 TypeofState typeof_state,
1293 Label* slow) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001294 Register context = esi;
1295 Register temp = edx;
1296
1297 Scope* s = scope();
1298 while (s != NULL) {
1299 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001300 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001301 // Check that extension is NULL.
1302 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1303 Immediate(0));
1304 __ j(not_equal, slow);
1305 }
1306 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001307 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001308 // Walk the rest of the chain without clobbering esi.
1309 context = temp;
1310 }
1311 // If no outer scope calls eval, we do not need to check more
1312 // context extensions. If we have reached an eval scope, we check
1313 // all extensions from this point.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001314 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001315 s = s->outer_scope();
1316 }
1317
1318 if (s != NULL && s->is_eval_scope()) {
1319 // Loop up the context chain. There is no frame effect so it is
1320 // safe to use raw labels here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001321 Label next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001322 if (!context.is(temp)) {
1323 __ mov(temp, context);
1324 }
1325 __ bind(&next);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001326 // Terminate at native context.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001327 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001328 Immediate(isolate()->factory()->native_context_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001329 __ j(equal, &fast, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001330 // Check that extension is NULL.
1331 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1332 __ j(not_equal, slow);
1333 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001334 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001335 __ jmp(&next);
1336 __ bind(&fast);
1337 }
1338
1339 // All extension objects were empty and it is safe to use a global
1340 // load IC call.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001341 __ mov(edx, GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001342 __ mov(ecx, var->name());
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00001343 ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
1344 ? NOT_CONTEXTUAL
1345 : CONTEXTUAL;
1346
1347 CallLoadIC(mode);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001348}
1349
1350
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001351MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1352 Label* slow) {
1353 ASSERT(var->IsContextSlot());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001354 Register context = esi;
1355 Register temp = ebx;
1356
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001357 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001358 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001359 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001360 // Check that extension is NULL.
1361 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1362 Immediate(0));
1363 __ j(not_equal, slow);
1364 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001365 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001366 // Walk the rest of the chain without clobbering esi.
1367 context = temp;
1368 }
1369 }
1370 // Check that last extension is NULL.
1371 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1372 __ j(not_equal, slow);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001373
1374 // This function is used only for loads, not stores, so it's safe to
1375 // return an esi-based operand (the write barrier cannot be allowed to
1376 // destroy the esi register).
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001377 return ContextOperand(context, var->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001378}
1379
1380
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001381void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1382 TypeofState typeof_state,
1383 Label* slow,
1384 Label* done) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001385 // Generate fast-case code for variables that might be shadowed by
1386 // eval-introduced variables. Eval is used a lot without
1387 // introducing variables. In those cases, we do not want to
1388 // perform a runtime call for all variables in the scope
1389 // containing the eval.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001390 if (var->mode() == DYNAMIC_GLOBAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001391 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001392 __ jmp(done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001393 } else if (var->mode() == DYNAMIC_LOCAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001394 Variable* local = var->local_if_not_shadowed();
1395 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001396 if (local->mode() == LET ||
1397 local->mode() == CONST ||
1398 local->mode() == CONST_HARMONY) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001399 __ cmp(eax, isolate()->factory()->the_hole_value());
1400 __ j(not_equal, done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001401 if (local->mode() == CONST) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001402 __ mov(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001403 } else { // LET || CONST_HARMONY
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001404 __ push(Immediate(var->name()));
1405 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1406 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001407 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001408 __ jmp(done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001409 }
1410}
1411
1412
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001413void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1414 // Record position before possible IC call.
1415 SetSourcePosition(proxy->position());
1416 Variable* var = proxy->var();
1417
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001418 // Three cases: global variables, lookup variables, and all other types of
1419 // variables.
1420 switch (var->location()) {
1421 case Variable::UNALLOCATED: {
mstarzinger@chromium.org1e71c4d2014-02-13 10:16:41 +00001422 Comment cmnt(masm_, "[ Global variable");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001423 // Use inline caching. Variable name is passed in ecx and the global
1424 // object in eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001425 __ mov(edx, GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001426 __ mov(ecx, var->name());
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00001427 CallLoadIC(CONTEXTUAL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001428 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001429 break;
1430 }
1431
1432 case Variable::PARAMETER:
1433 case Variable::LOCAL:
1434 case Variable::CONTEXT: {
mstarzinger@chromium.org1e71c4d2014-02-13 10:16:41 +00001435 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1436 : "[ Stack variable");
danno@chromium.orgc612e022011-11-10 11:38:15 +00001437 if (var->binding_needs_init()) {
1438 // var->scope() may be NULL when the proxy is located in eval code and
1439 // refers to a potential outside binding. Currently those bindings are
1440 // always looked up dynamically, i.e. in that case
1441 // var->location() == LOOKUP.
1442 // always holds.
1443 ASSERT(var->scope() != NULL);
1444
1445 // Check if the binding really needs an initialization check. The check
1446 // can be skipped in the following situation: we have a LET or CONST
1447 // binding in harmony mode, both the Variable and the VariableProxy have
1448 // the same declaration scope (i.e. they are both in global code, in the
1449 // same function or in the same eval code) and the VariableProxy is in
1450 // the source physically located after the initializer of the variable.
1451 //
1452 // We cannot skip any initialization checks for CONST in non-harmony
1453 // mode because const variables may be declared but never initialized:
1454 // if (false) { const x; }; var y = x;
1455 //
1456 // The condition on the declaration scopes is a conservative check for
1457 // nested functions that access a binding and are called before the
1458 // binding is initialized:
1459 // function() { f(); let x = 1; function f() { x = 2; } }
1460 //
1461 bool skip_init_check;
1462 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1463 skip_init_check = false;
jkummerow@chromium.orgac45fed2011-11-07 13:11:02 +00001464 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001465 // Check that we always have valid source position.
1466 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1467 ASSERT(proxy->position() != RelocInfo::kNoPosition);
1468 skip_init_check = var->mode() != CONST &&
1469 var->initializer_position() < proxy->position();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001470 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001471
1472 if (!skip_init_check) {
1473 // Let and const need a read barrier.
1474 Label done;
1475 GetVar(eax, var);
1476 __ cmp(eax, isolate()->factory()->the_hole_value());
1477 __ j(not_equal, &done, Label::kNear);
1478 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1479 // Throw a reference error when using an uninitialized let/const
1480 // binding in harmony mode.
1481 __ push(Immediate(var->name()));
1482 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1483 } else {
1484 // Uninitalized const bindings outside of harmony mode are unholed.
1485 ASSERT(var->mode() == CONST);
1486 __ mov(eax, isolate()->factory()->undefined_value());
1487 }
1488 __ bind(&done);
1489 context()->Plug(eax);
1490 break;
1491 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001492 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001493 context()->Plug(var);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001494 break;
1495 }
1496
1497 case Variable::LOOKUP: {
mstarzinger@chromium.org1e71c4d2014-02-13 10:16:41 +00001498 Comment cmnt(masm_, "[ Lookup variable");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001499 Label done, slow;
1500 // Generate code for loading from variables potentially shadowed
1501 // by eval-introduced variables.
1502 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1503 __ bind(&slow);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001504 __ push(esi); // Context.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001505 __ push(Immediate(var->name()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001506 __ CallRuntime(Runtime::kLoadContextSlot, 2);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001507 __ bind(&done);
1508 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001509 break;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001510 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001511 }
1512}
1513
1514
1515void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1516 Comment cmnt(masm_, "[ RegExpLiteral");
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001517 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001518 // Registers will be used as follows:
1519 // edi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001520 // ecx = literals array.
1521 // ebx = regexp literal.
1522 // eax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001523 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001524 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001525 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001526 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001527 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001528 __ cmp(ebx, isolate()->factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001529 __ j(not_equal, &materialized, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001530
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001531 // Create regexp literal using runtime function
1532 // Result will be in eax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001533 __ push(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001534 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1535 __ push(Immediate(expr->pattern()));
1536 __ push(Immediate(expr->flags()));
1537 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001538 __ mov(ebx, eax);
1539
1540 __ bind(&materialized);
1541 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1542 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001543 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001544 __ jmp(&allocated);
1545
1546 __ bind(&runtime_allocate);
1547 __ push(ebx);
1548 __ push(Immediate(Smi::FromInt(size)));
1549 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1550 __ pop(ebx);
1551
1552 __ bind(&allocated);
1553 // Copy the content into the newly allocated memory.
1554 // (Unroll copy loop once for better throughput).
1555 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1556 __ mov(edx, FieldOperand(ebx, i));
1557 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1558 __ mov(FieldOperand(eax, i), edx);
1559 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1560 }
1561 if ((size % (2 * kPointerSize)) != 0) {
1562 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1563 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1564 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001565 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001566}
1567
1568
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001569void FullCodeGenerator::EmitAccessor(Expression* expression) {
1570 if (expression == NULL) {
1571 __ push(Immediate(isolate()->factory()->null_value()));
1572 } else {
1573 VisitForStackValue(expression);
1574 }
1575}
1576
1577
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001578void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1579 Comment cmnt(masm_, "[ ObjectLiteral");
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001580
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001581 expr->BuildConstantProperties(isolate());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001582 Handle<FixedArray> constant_properties = expr->constant_properties();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001583 int flags = expr->fast_elements()
1584 ? ObjectLiteral::kFastElements
1585 : ObjectLiteral::kNoFlags;
1586 flags |= expr->has_function()
1587 ? ObjectLiteral::kHasFunction
1588 : ObjectLiteral::kNoFlags;
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001589 int properties_count = constant_properties->length() / 2;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001590 if ((FLAG_track_double_fields && expr->may_store_doubles()) ||
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001591 expr->depth() > 1 || Serializer::enabled() ||
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001592 flags != ObjectLiteral::kFastElements ||
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001593 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001594 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1595 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1596 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1597 __ push(Immediate(constant_properties));
1598 __ push(Immediate(Smi::FromInt(flags)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001599 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001600 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001601 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1602 __ mov(eax, FieldOperand(edi, JSFunction::kLiteralsOffset));
1603 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1604 __ mov(ecx, Immediate(constant_properties));
1605 __ mov(edx, Immediate(Smi::FromInt(flags)));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001606 FastCloneShallowObjectStub stub(properties_count);
1607 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001608 }
1609
1610 // If result_saved is true the result is on top of the stack. If
1611 // result_saved is false the result is in eax.
1612 bool result_saved = false;
1613
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001614 // Mark all computed expressions that are bound to a key that
1615 // is shadowed by a later occurrence of the same key. For the
1616 // marked expressions, no store code is emitted.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001617 expr->CalculateEmitStore(zone());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001618
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001619 AccessorTable accessor_table(zone());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001620 for (int i = 0; i < expr->properties()->length(); i++) {
1621 ObjectLiteral::Property* property = expr->properties()->at(i);
1622 if (property->IsCompileTimeValue()) continue;
1623
1624 Literal* key = property->key();
1625 Expression* value = property->value();
1626 if (!result_saved) {
1627 __ push(eax); // Save result on the stack
1628 result_saved = true;
1629 }
1630 switch (property->kind()) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001631 case ObjectLiteral::Property::CONSTANT:
1632 UNREACHABLE();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001633 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1634 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1635 // Fall through.
1636 case ObjectLiteral::Property::COMPUTED:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001637 if (key->value()->IsInternalizedString()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001638 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001639 VisitForAccumulatorValue(value);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001640 __ mov(ecx, Immediate(key->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001641 __ mov(edx, Operand(esp, 0));
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00001642 CallStoreIC(key->LiteralFeedbackId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001643 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1644 } else {
1645 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001646 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001647 break;
1648 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001649 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001650 VisitForStackValue(key);
1651 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001652 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001653 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1654 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001655 } else {
1656 __ Drop(3);
1657 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001658 break;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001659 case ObjectLiteral::Property::PROTOTYPE:
1660 __ push(Operand(esp, 0)); // Duplicate receiver.
1661 VisitForStackValue(value);
1662 if (property->emit_store()) {
1663 __ CallRuntime(Runtime::kSetPrototype, 2);
1664 } else {
1665 __ Drop(2);
1666 }
1667 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001668 case ObjectLiteral::Property::GETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001669 accessor_table.lookup(key)->second->getter = value;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001670 break;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001671 case ObjectLiteral::Property::SETTER:
1672 accessor_table.lookup(key)->second->setter = value;
1673 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001674 }
1675 }
1676
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001677 // Emit code to define accessors, using only a single call to the runtime for
1678 // each pair of corresponding getters and setters.
1679 for (AccessorTable::Iterator it = accessor_table.begin();
1680 it != accessor_table.end();
1681 ++it) {
1682 __ push(Operand(esp, 0)); // Duplicate receiver.
1683 VisitForStackValue(it->first);
1684 EmitAccessor(it->second->getter);
1685 EmitAccessor(it->second->setter);
1686 __ push(Immediate(Smi::FromInt(NONE)));
1687 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
1688 }
1689
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001690 if (expr->has_function()) {
1691 ASSERT(result_saved);
1692 __ push(Operand(esp, 0));
1693 __ CallRuntime(Runtime::kToFastProperties, 1);
1694 }
1695
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001696 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001697 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001698 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001699 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001700 }
1701}
1702
1703
1704void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1705 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001706
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001707 expr->BuildConstantElements(isolate());
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001708 int flags = expr->depth() == 1
1709 ? ArrayLiteral::kShallowElements
1710 : ArrayLiteral::kNoFlags;
1711
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001712 ZoneList<Expression*>* subexprs = expr->values();
1713 int length = subexprs->length();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001714 Handle<FixedArray> constant_elements = expr->constant_elements();
1715 ASSERT_EQ(2, constant_elements->length());
1716 ElementsKind constant_elements_kind =
1717 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001718 bool has_constant_fast_elements =
1719 IsFastObjectElementsKind(constant_elements_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001720 Handle<FixedArrayBase> constant_elements_values(
1721 FixedArrayBase::cast(constant_elements->get(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001722
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00001723 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00001724 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1725 // If the only customer of allocation sites is transitioning, then
1726 // we can turn it off if we don't have anywhere else to transition to.
1727 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1728 }
1729
erikcorry0ad885c2011-11-21 13:51:57 +00001730 Heap* heap = isolate()->heap();
1731 if (has_constant_fast_elements &&
1732 constant_elements_values->map() == heap->fixed_cow_array_map()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001733 // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
erikcorry0ad885c2011-11-21 13:51:57 +00001734 // change, so it's possible to specialize the stub in advance.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001736 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1737 __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
1738 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1739 __ mov(ecx, Immediate(constant_elements));
erikcorry0ad885c2011-11-21 13:51:57 +00001740 FastCloneShallowArrayStub stub(
1741 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00001742 allocation_site_mode,
erikcorry0ad885c2011-11-21 13:51:57 +00001743 length);
1744 __ CallStub(&stub);
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001745 } else if (expr->depth() > 1 || Serializer::enabled() ||
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001746 length > FastCloneShallowArrayStub::kMaximumClonedLength) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001747 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1748 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1749 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1750 __ push(Immediate(constant_elements));
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001751 __ push(Immediate(Smi::FromInt(flags)));
1752 __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001753 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001754 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001755 FLAG_smi_only_arrays);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001756 FastCloneShallowArrayStub::Mode mode =
1757 FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001758
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001759 // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
erikcorry0ad885c2011-11-21 13:51:57 +00001760 // change, so it's possible to specialize the stub in advance.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001761 if (has_constant_fast_elements) {
1762 mode = FastCloneShallowArrayStub::CLONE_ELEMENTS;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001763 }
1764
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001765 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1766 __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
1767 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1768 __ mov(ecx, Immediate(constant_elements));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001769 FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001770 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001771 }
1772
1773 bool result_saved = false; // Is the result saved to the stack?
1774
1775 // Emit code to evaluate all the non-constant subexpressions and to store
1776 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001777 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001778 Expression* subexpr = subexprs->at(i);
1779 // If the subexpression is a literal or a simple materialized literal it
1780 // is already set in the cloned array.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001781 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001782
1783 if (!result_saved) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001784 __ push(eax); // array literal.
1785 __ push(Immediate(Smi::FromInt(expr->literal_index())));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001786 result_saved = true;
1787 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001788 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001789
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001790 if (IsFastObjectElementsKind(constant_elements_kind)) {
1791 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1792 // cannot transition and don't need to call the runtime stub.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001793 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001794 __ mov(ebx, Operand(esp, kPointerSize)); // Copy of array literal.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001795 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1796 // Store the subexpression value in the array's elements.
1797 __ mov(FieldOperand(ebx, offset), result_register());
1798 // Update the write barrier for the array store.
1799 __ RecordWriteField(ebx, offset, result_register(), ecx,
1800 kDontSaveFPRegs,
1801 EMIT_REMEMBERED_SET,
1802 INLINE_SMI_CHECK);
1803 } else {
1804 // Store the subexpression value in the array's elements.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001805 __ mov(ecx, Immediate(Smi::FromInt(i)));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001806 StoreArrayLiteralElementStub stub;
1807 __ CallStub(&stub);
1808 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001809
1810 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001811 }
1812
1813 if (result_saved) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001814 __ add(esp, Immediate(kPointerSize)); // literal index
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001815 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001816 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001817 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001818 }
1819}
1820
1821
ager@chromium.org5c838252010-02-19 08:53:10 +00001822void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1823 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001824 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1825 // on the left-hand side.
1826 if (!expr->target()->IsValidLeftHandSide()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001827 VisitForEffect(expr->target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001828 return;
1829 }
1830
ager@chromium.org5c838252010-02-19 08:53:10 +00001831 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001832 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001833 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1834 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001835 Property* property = expr->target()->AsProperty();
1836 if (property != NULL) {
1837 assign_type = (property->key()->IsPropertyName())
1838 ? NAMED_PROPERTY
1839 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001840 }
1841
1842 // Evaluate LHS expression.
1843 switch (assign_type) {
1844 case VARIABLE:
1845 // Nothing to do here.
1846 break;
1847 case NAMED_PROPERTY:
1848 if (expr->is_compound()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001849 // We need the receiver both on the stack and in edx.
1850 VisitForStackValue(property->obj());
1851 __ mov(edx, Operand(esp, 0));
ager@chromium.org5c838252010-02-19 08:53:10 +00001852 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001853 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001854 }
1855 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001856 case KEYED_PROPERTY: {
ager@chromium.org5c838252010-02-19 08:53:10 +00001857 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001858 VisitForStackValue(property->obj());
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001859 VisitForStackValue(property->key());
1860 __ mov(edx, Operand(esp, kPointerSize)); // Object.
1861 __ mov(ecx, Operand(esp, 0)); // Key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001862 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001863 VisitForStackValue(property->obj());
1864 VisitForStackValue(property->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001865 }
1866 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001867 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001868 }
1869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001870 // For compound assignments we need another deoptimization point after the
1871 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001872 if (expr->is_compound()) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001873 AccumulatorValueContext result_context(this);
1874 { AccumulatorValueContext left_operand_context(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001875 switch (assign_type) {
1876 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001877 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001878 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001879 break;
1880 case NAMED_PROPERTY:
1881 EmitNamedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001882 PrepareForBailoutForId(property->LoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001883 break;
1884 case KEYED_PROPERTY:
1885 EmitKeyedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001886 PrepareForBailoutForId(property->LoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001887 break;
1888 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001889 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001890
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001891 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001892 __ push(eax); // Left operand goes on the stack.
1893 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001894
ricow@chromium.org65fae842010-08-25 15:26:24 +00001895 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1896 ? OVERWRITE_RIGHT
1897 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001898 SetSourcePosition(expr->position() + 1);
1899 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001900 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001901 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001902 mode,
1903 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001904 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001905 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001906 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001907 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001908
1909 // Deoptimization point in case the binary operation may have side effects.
1910 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001911 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001912 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001913 }
1914
1915 // Record source position before possible IC call.
1916 SetSourcePosition(expr->position());
1917
1918 // Store the value.
1919 switch (assign_type) {
1920 case VARIABLE:
1921 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001922 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001923 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1924 context()->Plug(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001925 break;
1926 case NAMED_PROPERTY:
1927 EmitNamedPropertyAssignment(expr);
1928 break;
1929 case KEYED_PROPERTY:
1930 EmitKeyedPropertyAssignment(expr);
1931 break;
1932 }
1933}
1934
1935
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001936void FullCodeGenerator::VisitYield(Yield* expr) {
1937 Comment cmnt(masm_, "[ Yield");
1938 // Evaluate yielded value first; the initial iterator definition depends on
1939 // this. It stays on the stack while we update the iterator.
1940 VisitForStackValue(expr->expression());
1941
1942 switch (expr->yield_kind()) {
danno@chromium.org41728482013-06-12 22:31:22 +00001943 case Yield::SUSPEND:
1944 // Pop value from top-of-stack slot; box result into result register.
1945 EmitCreateIteratorResult(false);
1946 __ push(result_register());
1947 // Fall through.
1948 case Yield::INITIAL: {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001949 Label suspend, continuation, post_runtime, resume;
1950
1951 __ jmp(&suspend);
1952
1953 __ bind(&continuation);
1954 __ jmp(&resume);
1955
1956 __ bind(&suspend);
1957 VisitForAccumulatorValue(expr->generator_object());
1958 ASSERT(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1959 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
1960 Immediate(Smi::FromInt(continuation.pos())));
1961 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
1962 __ mov(ecx, esi);
1963 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
1964 kDontSaveFPRegs);
1965 __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
1966 __ cmp(esp, ebx);
1967 __ j(equal, &post_runtime);
1968 __ push(eax); // generator object
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001969 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
1970 __ mov(context_register(),
1971 Operand(ebp, StandardFrameConstants::kContextOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001972 __ bind(&post_runtime);
danno@chromium.org41728482013-06-12 22:31:22 +00001973 __ pop(result_register());
1974 EmitReturnSequence();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001975
1976 __ bind(&resume);
1977 context()->Plug(result_register());
1978 break;
1979 }
1980
1981 case Yield::FINAL: {
1982 VisitForAccumulatorValue(expr->generator_object());
1983 __ mov(FieldOperand(result_register(),
1984 JSGeneratorObject::kContinuationOffset),
1985 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
danno@chromium.org41728482013-06-12 22:31:22 +00001986 // Pop value from top-of-stack slot, box result into result register.
1987 EmitCreateIteratorResult(true);
1988 EmitUnwindBeforeReturn();
1989 EmitReturnSequence();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001990 break;
1991 }
1992
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001993 case Yield::DELEGATING: {
1994 VisitForStackValue(expr->generator_object());
1995
1996 // Initial stack layout is as follows:
1997 // [sp + 1 * kPointerSize] iter
1998 // [sp + 0 * kPointerSize] g
1999
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002000 Label l_catch, l_try, l_suspend, l_continuation, l_resume;
2001 Label l_next, l_call, l_loop;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002002 // Initial send value is undefined.
2003 __ mov(eax, isolate()->factory()->undefined_value());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002004 __ jmp(&l_next);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002005
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002006 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002007 __ bind(&l_catch);
2008 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002009 __ mov(ecx, isolate()->factory()->throw_string()); // "throw"
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002010 __ push(ecx); // "throw"
2011 __ push(Operand(esp, 2 * kPointerSize)); // iter
2012 __ push(eax); // exception
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002013 __ jmp(&l_call);
2014
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002015 // try { received = %yield result }
2016 // Shuffle the received result above a try handler and yield it without
2017 // re-boxing.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002018 __ bind(&l_try);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002019 __ pop(eax); // result
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002020 __ PushTryHandler(StackHandler::CATCH, expr->index());
2021 const int handler_size = StackHandlerConstants::kSize;
danno@chromium.org41728482013-06-12 22:31:22 +00002022 __ push(eax); // result
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002023 __ jmp(&l_suspend);
2024 __ bind(&l_continuation);
2025 __ jmp(&l_resume);
2026 __ bind(&l_suspend);
2027 const int generator_object_depth = kPointerSize + handler_size;
2028 __ mov(eax, Operand(esp, generator_object_depth));
2029 __ push(eax); // g
2030 ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
2031 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
2032 Immediate(Smi::FromInt(l_continuation.pos())));
2033 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
2034 __ mov(ecx, esi);
2035 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
2036 kDontSaveFPRegs);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002037 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2038 __ mov(context_register(),
2039 Operand(ebp, StandardFrameConstants::kContextOffset));
danno@chromium.org41728482013-06-12 22:31:22 +00002040 __ pop(eax); // result
2041 EmitReturnSequence();
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002042 __ bind(&l_resume); // received in eax
2043 __ PopTryHandler();
2044
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002045 // receiver = iter; f = iter.next; arg = received;
2046 __ bind(&l_next);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002047 __ mov(ecx, isolate()->factory()->next_string()); // "next"
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002048 __ push(ecx);
2049 __ push(Operand(esp, 2 * kPointerSize)); // iter
2050 __ push(eax); // received
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002051
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002052 // result = receiver[f](arg);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002053 __ bind(&l_call);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002054 __ mov(edx, Operand(esp, kPointerSize));
2055 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00002056 CallIC(ic, TypeFeedbackId::None());
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002057 __ mov(edi, eax);
2058 __ mov(Operand(esp, 2 * kPointerSize), edi);
2059 CallFunctionStub stub(1, CALL_AS_METHOD);
2060 __ CallStub(&stub);
2061
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002062 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002063 __ Drop(1); // The function is still on the stack; drop it.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002064
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002065 // if (!result.done) goto l_try;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002066 __ bind(&l_loop);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002067 __ push(eax); // save result
2068 __ mov(edx, eax); // result
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002069 __ mov(ecx, isolate()->factory()->done_string()); // "done"
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002070 CallLoadIC(NOT_CONTEXTUAL); // result.done in eax
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002071 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
2072 CallIC(bool_ic);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002073 __ test(eax, eax);
2074 __ j(zero, &l_try);
2075
2076 // result.value
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002077 __ pop(edx); // result
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002078 __ mov(ecx, isolate()->factory()->value_string()); // "value"
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002079 CallLoadIC(NOT_CONTEXTUAL); // result.value in eax
2080 context()->DropAndPlug(2, eax); // drop iter and g
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002081 break;
2082 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002083 }
2084}
2085
2086
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002087void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2088 Expression *value,
2089 JSGeneratorObject::ResumeMode resume_mode) {
2090 // The value stays in eax, and is ultimately read by the resumed generator, as
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002091 // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
2092 // is read to throw the value when the resumed generator is already closed.
2093 // ebx will hold the generator object until the activation has been resumed.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002094 VisitForStackValue(generator);
2095 VisitForAccumulatorValue(value);
2096 __ pop(ebx);
2097
2098 // Check generator state.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002099 Label wrong_state, closed_state, done;
2100 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
2101 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002102 __ cmp(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
2103 Immediate(Smi::FromInt(0)));
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002104 __ j(equal, &closed_state);
2105 __ j(less, &wrong_state);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002106
2107 // Load suspended function and context.
2108 __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
2109 __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
2110
2111 // Push receiver.
2112 __ push(FieldOperand(ebx, JSGeneratorObject::kReceiverOffset));
2113
2114 // Push holes for arguments to generator function.
2115 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2116 __ mov(edx,
2117 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2118 __ mov(ecx, isolate()->factory()->the_hole_value());
2119 Label push_argument_holes, push_frame;
2120 __ bind(&push_argument_holes);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002121 __ sub(edx, Immediate(Smi::FromInt(1)));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002122 __ j(carry, &push_frame);
2123 __ push(ecx);
2124 __ jmp(&push_argument_holes);
2125
2126 // Enter a new JavaScript frame, and initialize its slots as they were when
2127 // the generator was suspended.
2128 Label resume_frame;
2129 __ bind(&push_frame);
2130 __ call(&resume_frame);
2131 __ jmp(&done);
2132 __ bind(&resume_frame);
2133 __ push(ebp); // Caller's frame pointer.
2134 __ mov(ebp, esp);
2135 __ push(esi); // Callee's context.
2136 __ push(edi); // Callee's JS Function.
2137
2138 // Load the operand stack size.
2139 __ mov(edx, FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset));
2140 __ mov(edx, FieldOperand(edx, FixedArray::kLengthOffset));
2141 __ SmiUntag(edx);
2142
2143 // If we are sending a value and there is no operand stack, we can jump back
2144 // in directly.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002145 if (resume_mode == JSGeneratorObject::NEXT) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002146 Label slow_resume;
2147 __ cmp(edx, Immediate(0));
2148 __ j(not_zero, &slow_resume);
2149 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2150 __ mov(ecx, FieldOperand(ebx, JSGeneratorObject::kContinuationOffset));
2151 __ SmiUntag(ecx);
2152 __ add(edx, ecx);
2153 __ mov(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
2154 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
2155 __ jmp(edx);
2156 __ bind(&slow_resume);
2157 }
2158
2159 // Otherwise, we push holes for the operand stack and call the runtime to fix
2160 // up the stack and the handlers.
2161 Label push_operand_holes, call_resume;
2162 __ bind(&push_operand_holes);
2163 __ sub(edx, Immediate(1));
2164 __ j(carry, &call_resume);
2165 __ push(ecx);
2166 __ jmp(&push_operand_holes);
2167 __ bind(&call_resume);
2168 __ push(ebx);
2169 __ push(result_register());
2170 __ Push(Smi::FromInt(resume_mode));
2171 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
2172 // Not reached: the runtime call returns elsewhere.
danno@chromium.org59400602013-08-13 17:09:37 +00002173 __ Abort(kGeneratorFailedToResume);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002174
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002175 // Reach here when generator is closed.
2176 __ bind(&closed_state);
2177 if (resume_mode == JSGeneratorObject::NEXT) {
2178 // Return completed iterator result when generator is closed.
2179 __ push(Immediate(isolate()->factory()->undefined_value()));
2180 // Pop value from top-of-stack slot; box result into result register.
2181 EmitCreateIteratorResult(true);
2182 } else {
2183 // Throw the provided value.
2184 __ push(eax);
2185 __ CallRuntime(Runtime::kThrow, 1);
2186 }
2187 __ jmp(&done);
2188
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002189 // Throw error if we attempt to operate on a running generator.
2190 __ bind(&wrong_state);
2191 __ push(ebx);
2192 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
2193
2194 __ bind(&done);
2195 context()->Plug(result_register());
2196}
2197
2198
danno@chromium.org41728482013-06-12 22:31:22 +00002199void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002200 Label gc_required;
2201 Label allocated;
2202
2203 Handle<Map> map(isolate()->native_context()->generator_result_map());
2204
2205 __ Allocate(map->instance_size(), eax, ecx, edx, &gc_required, TAG_OBJECT);
danno@chromium.org41728482013-06-12 22:31:22 +00002206 __ jmp(&allocated);
2207
2208 __ bind(&gc_required);
2209 __ Push(Smi::FromInt(map->instance_size()));
2210 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
2211 __ mov(context_register(),
2212 Operand(ebp, StandardFrameConstants::kContextOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002213
2214 __ bind(&allocated);
2215 __ mov(ebx, map);
2216 __ pop(ecx);
2217 __ mov(edx, isolate()->factory()->ToBoolean(done));
2218 ASSERT_EQ(map->instance_size(), 5 * kPointerSize);
2219 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
2220 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
2221 isolate()->factory()->empty_fixed_array());
2222 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
2223 isolate()->factory()->empty_fixed_array());
2224 __ mov(FieldOperand(eax, JSGeneratorObject::kResultValuePropertyOffset), ecx);
2225 __ mov(FieldOperand(eax, JSGeneratorObject::kResultDonePropertyOffset), edx);
2226
2227 // Only the value field needs a write barrier, as the other values are in the
2228 // root set.
2229 __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset,
2230 ecx, edx, kDontSaveFPRegs);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002231}
2232
2233
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002234void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
2235 SetSourcePosition(prop->position());
2236 Literal* key = prop->key()->AsLiteral();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002237 ASSERT(!key->value()->IsSmi());
2238 __ mov(ecx, Immediate(key->value()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002239 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002240}
2241
2242
2243void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
2244 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002245 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00002246 CallIC(ic, prop->PropertyFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002247}
2248
2249
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002250void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002251 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002252 OverwriteMode mode,
2253 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002254 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002255 // Do combined smi check of the operands. Left operand is on the
2256 // stack. Right operand is in eax.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002257 Label smi_case, done, stub_call;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002258 __ pop(edx);
2259 __ mov(ecx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002260 __ or_(eax, edx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002261 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002262 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002263
2264 __ bind(&stub_call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002265 __ mov(eax, ecx);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002266 BinaryOpICStub stub(op, mode);
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00002267 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002268 patch_site.EmitPatchInfo();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002269 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002270
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002271 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002272 __ bind(&smi_case);
2273 __ mov(eax, edx); // Copy left operand in case of a stub call.
2274
2275 switch (op) {
2276 case Token::SAR:
2277 __ SmiUntag(eax);
2278 __ SmiUntag(ecx);
2279 __ sar_cl(eax); // No checks of result necessary
2280 __ SmiTag(eax);
2281 break;
2282 case Token::SHL: {
2283 Label result_ok;
2284 __ SmiUntag(eax);
2285 __ SmiUntag(ecx);
2286 __ shl_cl(eax);
2287 // Check that the *signed* result fits in a smi.
2288 __ cmp(eax, 0xc0000000);
2289 __ j(positive, &result_ok);
2290 __ SmiTag(ecx);
2291 __ jmp(&stub_call);
2292 __ bind(&result_ok);
2293 __ SmiTag(eax);
2294 break;
2295 }
2296 case Token::SHR: {
2297 Label result_ok;
2298 __ SmiUntag(eax);
2299 __ SmiUntag(ecx);
2300 __ shr_cl(eax);
2301 __ test(eax, Immediate(0xc0000000));
2302 __ j(zero, &result_ok);
2303 __ SmiTag(ecx);
2304 __ jmp(&stub_call);
2305 __ bind(&result_ok);
2306 __ SmiTag(eax);
2307 break;
2308 }
2309 case Token::ADD:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002310 __ add(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002311 __ j(overflow, &stub_call);
2312 break;
2313 case Token::SUB:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002314 __ sub(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002315 __ j(overflow, &stub_call);
2316 break;
2317 case Token::MUL: {
2318 __ SmiUntag(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002319 __ imul(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002320 __ j(overflow, &stub_call);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002321 __ test(eax, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002322 __ j(not_zero, &done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002323 __ mov(ebx, edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002324 __ or_(ebx, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002325 __ j(negative, &stub_call);
2326 break;
2327 }
2328 case Token::BIT_OR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002329 __ or_(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002330 break;
2331 case Token::BIT_AND:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002332 __ and_(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002333 break;
2334 case Token::BIT_XOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002335 __ xor_(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002336 break;
2337 default:
2338 UNREACHABLE();
2339 }
2340
2341 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002342 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002343}
2344
2345
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002346void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
2347 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00002348 OverwriteMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002349 __ pop(edx);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002350 BinaryOpICStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002351 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00002352 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002353 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002354 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002355}
2356
2357
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002358void FullCodeGenerator::EmitAssignment(Expression* expr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002359 // Invalid left-hand sides are rewritten by the parser to have a 'throw
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002360 // ReferenceError' on the left-hand side.
2361 if (!expr->IsValidLeftHandSide()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002362 VisitForEffect(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002363 return;
2364 }
2365
2366 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002367 // slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002368 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2369 LhsKind assign_type = VARIABLE;
2370 Property* prop = expr->AsProperty();
2371 if (prop != NULL) {
2372 assign_type = (prop->key()->IsPropertyName())
2373 ? NAMED_PROPERTY
2374 : KEYED_PROPERTY;
2375 }
2376
2377 switch (assign_type) {
2378 case VARIABLE: {
2379 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002380 EffectContext context(this);
2381 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002382 break;
2383 }
2384 case NAMED_PROPERTY: {
2385 __ push(eax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002386 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002387 __ mov(edx, eax);
2388 __ pop(eax); // Restore value.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002389 __ mov(ecx, prop->key()->AsLiteral()->value());
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00002390 CallStoreIC();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002391 break;
2392 }
2393 case KEYED_PROPERTY: {
2394 __ push(eax); // Preserve value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002395 VisitForStackValue(prop->obj());
2396 VisitForAccumulatorValue(prop->key());
2397 __ mov(ecx, eax);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002398 __ pop(edx); // Receiver.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002399 __ pop(eax); // Restore value.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002400 Handle<Code> ic = is_classic_mode()
2401 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2402 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002403 CallIC(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002404 break;
2405 }
2406 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002407 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002408}
2409
2410
machenbach@chromium.orgbfd1d202014-02-19 01:05:38 +00002411void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2412 Variable* var, MemOperand location) {
2413 __ mov(location, eax);
2414 if (var->IsContextSlot()) {
2415 __ mov(edx, eax);
2416 int offset = Context::SlotOffset(var->index());
2417 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
2418 }
2419}
2420
2421
2422void FullCodeGenerator::EmitCallStoreContextSlot(
2423 Handle<String> name, LanguageMode mode) {
2424 __ push(eax); // Value.
2425 __ push(esi); // Context.
2426 __ push(Immediate(name));
2427 __ push(Immediate(Smi::FromInt(mode)));
2428 __ CallRuntime(Runtime::kStoreContextSlot, 4);
2429}
2430
2431
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002432void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002433 Token::Value op) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002434 if (var->IsUnallocated()) {
2435 // Global var, const, or let.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002436 __ mov(ecx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002437 __ mov(edx, GlobalObjectOperand());
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00002438 CallStoreIC();
machenbach@chromium.orgbfd1d202014-02-19 01:05:38 +00002439
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002440 } else if (op == Token::INIT_CONST) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002441 // Const initializers need a write barrier.
2442 ASSERT(!var->IsParameter()); // No const parameters.
machenbach@chromium.orgbfd1d202014-02-19 01:05:38 +00002443 if (var->IsLookupSlot()) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002444 __ push(eax);
2445 __ push(esi);
2446 __ push(Immediate(var->name()));
2447 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
machenbach@chromium.orgbfd1d202014-02-19 01:05:38 +00002448 } else {
2449 ASSERT(var->IsStackLocal() || var->IsContextSlot());
2450 Label skip;
2451 MemOperand location = VarOperand(var, ecx);
2452 __ mov(edx, location);
2453 __ cmp(edx, isolate()->factory()->the_hole_value());
2454 __ j(not_equal, &skip, Label::kNear);
2455 EmitStoreToStackLocalOrContextSlot(var, location);
2456 __ bind(&skip);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002457 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002458
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002459 } else if (var->mode() == LET && op != Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002460 // Non-initializing assignment to let variable needs a write barrier.
2461 if (var->IsLookupSlot()) {
machenbach@chromium.orgbfd1d202014-02-19 01:05:38 +00002462 EmitCallStoreContextSlot(var->name(), language_mode());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002463 } else {
2464 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
2465 Label assign;
2466 MemOperand location = VarOperand(var, ecx);
2467 __ mov(edx, location);
2468 __ cmp(edx, isolate()->factory()->the_hole_value());
2469 __ j(not_equal, &assign, Label::kNear);
2470 __ push(Immediate(var->name()));
2471 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2472 __ bind(&assign);
machenbach@chromium.orgbfd1d202014-02-19 01:05:38 +00002473 EmitStoreToStackLocalOrContextSlot(var, location);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002474 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002475
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002476 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
2477 // Assignment to var or initializing assignment to let/const
2478 // in harmony mode.
machenbach@chromium.orgbfd1d202014-02-19 01:05:38 +00002479 if (var->IsLookupSlot()) {
2480 EmitCallStoreContextSlot(var->name(), language_mode());
2481 } else {
2482 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002483 MemOperand location = VarOperand(var, ecx);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002484 if (generate_debug_code_ && op == Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002485 // Check for an uninitialized let binding.
2486 __ mov(edx, location);
2487 __ cmp(edx, isolate()->factory()->the_hole_value());
danno@chromium.org59400602013-08-13 17:09:37 +00002488 __ Check(equal, kLetBindingReInitialization);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002489 }
machenbach@chromium.orgbfd1d202014-02-19 01:05:38 +00002490 EmitStoreToStackLocalOrContextSlot(var, location);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002491 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002492 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002493 // Non-initializing assignments to consts are ignored.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002494}
2495
2496
2497void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2498 // Assignment to a property, using a named store IC.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002499 // eax : value
2500 // esp[0] : receiver
2501
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002502 Property* prop = expr->target()->AsProperty();
2503 ASSERT(prop != NULL);
2504 ASSERT(prop->key()->AsLiteral() != NULL);
2505
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002506 // Record source code position before IC call.
2507 SetSourcePosition(expr->position());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002508 __ mov(ecx, prop->key()->AsLiteral()->value());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002509 __ pop(edx);
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00002510 CallStoreIC(expr->AssignmentFeedbackId());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002511 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2512 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002513}
2514
2515
2516void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2517 // Assignment to a property, using a keyed store IC.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002518 // eax : value
2519 // esp[0] : key
2520 // esp[kPointerSize] : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002521
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002522 __ pop(ecx); // Key.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002523 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002524 // Record source code position before IC call.
2525 SetSourcePosition(expr->position());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002526 Handle<Code> ic = is_classic_mode()
2527 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2528 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00002529 CallIC(ic, expr->AssignmentFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002530
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002531 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002532 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002533}
2534
2535
2536void FullCodeGenerator::VisitProperty(Property* expr) {
2537 Comment cmnt(masm_, "[ Property");
2538 Expression* key = expr->key();
2539
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002540 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002541 VisitForAccumulatorValue(expr->obj());
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002542 __ mov(edx, result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002543 EmitNamedPropertyLoad(expr);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002544 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002545 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002546 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002547 VisitForStackValue(expr->obj());
2548 VisitForAccumulatorValue(expr->key());
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002549 __ pop(edx); // Object.
2550 __ mov(ecx, result_register()); // Key.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002551 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002552 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002553 }
2554}
2555
2556
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002557void FullCodeGenerator::CallIC(Handle<Code> code,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002558 TypeFeedbackId ast_id) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002559 ic_total_count_++;
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002560 __ call(code, RelocInfo::CODE_TARGET, ast_id);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002561}
2562
2563
2564
2565
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002566// Code common for calls using the IC.
2567void FullCodeGenerator::EmitCallWithIC(Call* expr) {
2568 Expression* callee = expr->expression();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002569 ZoneList<Expression*>* args = expr->arguments();
2570 int arg_count = args->length();
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002571
2572 CallFunctionFlags flags;
2573 // Get the target function.
2574 if (callee->IsVariableProxy()) {
2575 { StackValueContext context(this);
2576 EmitVariableLoad(callee->AsVariableProxy());
2577 PrepareForBailout(callee, NO_REGISTERS);
2578 }
2579 // Push undefined as receiver. This is patched in the method prologue if it
2580 // is a classic mode method.
2581 __ push(Immediate(isolate()->factory()->undefined_value()));
2582 flags = NO_CALL_FUNCTION_FLAGS;
2583 } else {
2584 // Load the function from the receiver.
2585 ASSERT(callee->IsProperty());
2586 __ mov(edx, Operand(esp, 0));
2587 EmitNamedPropertyLoad(callee->AsProperty());
2588 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2589 // Push the target function under the receiver.
2590 __ push(Operand(esp, 0));
2591 __ mov(Operand(esp, kPointerSize), eax);
2592 flags = CALL_AS_METHOD;
2593 }
2594
2595 // Load the arguments.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002596 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002597 for (int i = 0; i < arg_count; i++) {
2598 VisitForStackValue(args->at(i));
2599 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002600 }
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002601
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002602 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002603 SetSourcePosition(expr->position());
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002604 CallFunctionStub stub(arg_count, flags);
2605 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2606 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002607 RecordJSReturnSite(expr);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002608
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002609 // Restore context register.
2610 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002611
2612 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002613}
2614
2615
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002616// Code common for calls using the IC.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002617void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002618 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002619 // Load the key.
2620 VisitForAccumulatorValue(key);
2621
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002622 Expression* callee = expr->expression();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002623 ZoneList<Expression*>* args = expr->arguments();
2624 int arg_count = args->length();
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002625
2626 // Load the function from the receiver.
2627 ASSERT(callee->IsProperty());
2628 __ mov(edx, Operand(esp, 0));
2629 // Move the key into the right register for the keyed load IC.
2630 __ mov(ecx, eax);
2631 EmitKeyedPropertyLoad(callee->AsProperty());
2632 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2633
2634 // Push the target function under the receiver.
2635 __ push(Operand(esp, 0));
2636 __ mov(Operand(esp, kPointerSize), eax);
2637
2638 // Load the arguments.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002639 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002640 for (int i = 0; i < arg_count; i++) {
2641 VisitForStackValue(args->at(i));
2642 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002643 }
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002644
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002645 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002646 SetSourcePosition(expr->position());
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002647 CallFunctionStub stub(arg_count, CALL_AS_METHOD);
2648 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2649 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002650 RecordJSReturnSite(expr);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002651
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002652 // Restore context register.
2653 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002654
2655 context()->DropAndPlug(1, eax);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002656}
2657
2658
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002659void FullCodeGenerator::EmitCallWithStub(Call* expr) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002660 // Code common for calls using the call stub.
2661 ZoneList<Expression*>* args = expr->arguments();
2662 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002663 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002664 for (int i = 0; i < arg_count; i++) {
2665 VisitForStackValue(args->at(i));
2666 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002667 }
2668 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002669 SetSourcePosition(expr->position());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002670
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002671 Handle<Object> uninitialized =
machenbach@chromium.org7d6bc7d2014-02-11 08:13:48 +00002672 TypeFeedbackInfo::UninitializedSentinel(isolate());
2673 StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized);
2674 __ LoadHeapObject(ebx, FeedbackVector());
2675 __ mov(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot())));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002676
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002677 // Record call targets in unoptimized code.
2678 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002679 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
machenbach@chromium.org7d6bc7d2014-02-11 08:13:48 +00002680 __ CallStub(&stub);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002681
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002682 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002683 // Restore context register.
2684 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002685 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002686}
2687
2688
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002689void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002690 // Push copy of the first argument or undefined if it doesn't exist.
2691 if (arg_count > 0) {
2692 __ push(Operand(esp, arg_count * kPointerSize));
2693 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002694 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002695 }
2696
2697 // Push the receiver of the enclosing function.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002698 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002699 // Push the language mode.
2700 __ push(Immediate(Smi::FromInt(language_mode())));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002701
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002702 // Push the start position of the scope the calls resides in.
2703 __ push(Immediate(Smi::FromInt(scope()->start_position())));
2704
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002705 // Do the runtime call.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002706 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002707}
2708
2709
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002710void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002711#ifdef DEBUG
2712 // We want to verify that RecordJSReturnSite gets called on all paths
2713 // through this function. Avoid early returns.
2714 expr->return_is_recorded_ = false;
2715#endif
2716
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002717 Comment cmnt(masm_, "[ Call");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002718 Expression* callee = expr->expression();
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002719 Call::CallType call_type = expr->GetCallType(isolate());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002720
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002721 if (call_type == Call::POSSIBLY_EVAL_CALL) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002722 // In a call to eval, we first call %ResolvePossiblyDirectEval to
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002723 // resolve the function we need to call and the receiver of the call.
2724 // Then we call the resolved function using the given arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002725 ZoneList<Expression*>* args = expr->arguments();
2726 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002727 { PreservePositionScope pos_scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002728 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002729 // Reserved receiver slot.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002730 __ push(Immediate(isolate()->factory()->undefined_value()));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002731 // Push the arguments.
2732 for (int i = 0; i < arg_count; i++) {
2733 VisitForStackValue(args->at(i));
2734 }
2735
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002736 // Push a copy of the function (found below the arguments) and
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002737 // resolve eval.
2738 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002739 EmitResolvePossiblyDirectEval(arg_count);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002740
2741 // The runtime call returns a pair of values in eax (function) and
2742 // edx (receiver). Touch up the stack with the right values.
2743 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2744 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002745 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002746 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002747 SetSourcePosition(expr->position());
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002748 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002749 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002750 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002751 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002752 // Restore context register.
2753 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002754 context()->DropAndPlug(1, eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002755
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002756 } else if (call_type == Call::GLOBAL_CALL) {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002757 EmitCallWithIC(expr);
2758
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002759 } else if (call_type == Call::LOOKUP_SLOT_CALL) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002760 // Call to a lookup slot (dynamically introduced variable).
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002761 VariableProxy* proxy = callee->AsVariableProxy();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002762 Label slow, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002763 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002764 // Generate code for loading from variables potentially shadowed by
2765 // eval-introduced variables.
2766 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002767 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002768 __ bind(&slow);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002769 // Call the runtime to find the function to call (returned in eax) and
2770 // the object holding it (returned in edx).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002771 __ push(context_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002772 __ push(Immediate(proxy->name()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002773 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2774 __ push(eax); // Function.
2775 __ push(edx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002776
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002777 // If fast case code has been generated, emit code to push the function
2778 // and receiver and have the slow path jump around this code.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002779 if (done.is_linked()) {
2780 Label call;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002781 __ jmp(&call, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002782 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002783 // Push function.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002784 __ push(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002785 // The receiver is implicitly the global receiver. Indicate this by
2786 // passing the hole to the call function stub.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002787 __ push(Immediate(isolate()->factory()->undefined_value()));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002788 __ bind(&call);
2789 }
2790
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002791 // The receiver is either the global receiver or an object found by
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002792 // LoadContextSlot.
2793 EmitCallWithStub(expr);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002794
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002795 } else if (call_type == Call::PROPERTY_CALL) {
2796 Property* property = callee->AsProperty();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002797 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002798 VisitForStackValue(property->obj());
2799 }
2800 if (property->key()->IsPropertyName()) {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002801 EmitCallWithIC(expr);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002802 } else {
2803 EmitKeyedCallWithIC(expr, property->key());
2804 }
2805
2806 } else {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002807 ASSERT(call_type == Call::OTHER_CALL);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002808 // Call to an arbitrary expression not handled specially above.
2809 { PreservePositionScope scope(masm()->positions_recorder());
2810 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002811 }
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002812 __ push(Immediate(isolate()->factory()->undefined_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002813 // Emit function call.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002814 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002815 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002816
2817#ifdef DEBUG
2818 // RecordJSReturnSite should have been called.
2819 ASSERT(expr->return_is_recorded_);
2820#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002821}
2822
2823
2824void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2825 Comment cmnt(masm_, "[ CallNew");
2826 // According to ECMA-262, section 11.2.2, page 44, the function
2827 // expression in new calls must be evaluated before the
2828 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002829
ricow@chromium.org65fae842010-08-25 15:26:24 +00002830 // Push constructor on the stack. If it's not a function it's used as
2831 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2832 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002833 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002834
2835 // Push the arguments ("left-to-right") on the stack.
2836 ZoneList<Expression*>* args = expr->arguments();
2837 int arg_count = args->length();
2838 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002839 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002840 }
2841
2842 // Call the construct call builtin that handles allocation and
2843 // constructor invocation.
2844 SetSourcePosition(expr->position());
2845
ricow@chromium.org65fae842010-08-25 15:26:24 +00002846 // Load function and argument count into edi and eax.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002847 __ Set(eax, Immediate(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002848 __ mov(edi, Operand(esp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002849
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002850 // Record call targets in unoptimized code.
2851 Handle<Object> uninitialized =
machenbach@chromium.org7d6bc7d2014-02-11 08:13:48 +00002852 TypeFeedbackInfo::UninitializedSentinel(isolate());
2853 StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized);
2854 __ LoadHeapObject(ebx, FeedbackVector());
2855 __ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot())));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002856
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002857 CallConstructStub stub(RECORD_CALL_TARGET);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002858 __ call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL);
ulan@chromium.org967e2702012-02-28 09:49:15 +00002859 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002860 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002861}
2862
2863
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002864void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2865 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002866 ASSERT(args->length() == 1);
2867
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002868 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002869
2870 Label materialize_true, materialize_false;
2871 Label* if_true = NULL;
2872 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002873 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002874 context()->PrepareTest(&materialize_true, &materialize_false,
2875 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002876
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002877 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002878 __ test(eax, Immediate(kSmiTagMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002879 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002880
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002881 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002882}
2883
2884
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002885void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2886 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002887 ASSERT(args->length() == 1);
2888
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002889 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002890
2891 Label materialize_true, materialize_false;
2892 Label* if_true = NULL;
2893 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002894 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002895 context()->PrepareTest(&materialize_true, &materialize_false,
2896 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002897
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002898 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002899 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002900 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002901
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002902 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002903}
2904
2905
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002906void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2907 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002908 ASSERT(args->length() == 1);
2909
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002910 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002911
2912 Label materialize_true, materialize_false;
2913 Label* if_true = NULL;
2914 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002915 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002916 context()->PrepareTest(&materialize_true, &materialize_false,
2917 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002918
whesse@chromium.org7b260152011-06-20 15:33:18 +00002919 __ JumpIfSmi(eax, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002920 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002921 __ j(equal, if_true);
2922 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2923 // Undetectable objects behave like undefined when tested with typeof.
2924 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2925 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2926 __ j(not_zero, if_false);
2927 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002928 __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002929 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002930 __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002931 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002932 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002933
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002934 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002935}
2936
2937
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002938void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2939 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002940 ASSERT(args->length() == 1);
2941
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002942 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002943
2944 Label materialize_true, materialize_false;
2945 Label* if_true = NULL;
2946 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002947 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002948 context()->PrepareTest(&materialize_true, &materialize_false,
2949 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002950
whesse@chromium.org7b260152011-06-20 15:33:18 +00002951 __ JumpIfSmi(eax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002952 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002953 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002954 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002955
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002956 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002957}
2958
2959
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002960void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2961 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002962 ASSERT(args->length() == 1);
2963
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002964 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002965
2966 Label materialize_true, materialize_false;
2967 Label* if_true = NULL;
2968 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002969 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002970 context()->PrepareTest(&materialize_true, &materialize_false,
2971 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002972
whesse@chromium.org7b260152011-06-20 15:33:18 +00002973 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002974 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2975 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2976 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002977 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002978 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002979
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002980 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002981}
2982
2983
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002984void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002985 CallRuntime* expr) {
2986 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002987 ASSERT(args->length() == 1);
2988
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002989 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002990
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002991 Label materialize_true, materialize_false, skip_lookup;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002992 Label* if_true = NULL;
2993 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002994 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002995 context()->PrepareTest(&materialize_true, &materialize_false,
2996 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002997
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002998 __ AssertNotSmi(eax);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002999
3000 // Check whether this map has already been checked to be safe for default
3001 // valueOf.
3002 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3003 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
3004 1 << Map::kStringWrapperSafeForDefaultValueOf);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003005 __ j(not_zero, &skip_lookup);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003006
3007 // Check for fast case object. Return false for slow case objects.
3008 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
3009 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003010 __ cmp(ecx, isolate()->factory()->hash_table_map());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003011 __ j(equal, if_false);
3012
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003013 // Look for valueOf string in the descriptor array, and indicate false if
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003014 // found. Since we omit an enumeration index check, if it is added via a
3015 // transition that shares its descriptor array, this is a false positive.
3016 Label entry, loop, done;
3017
3018 // Skip loop if no descriptors are valid.
3019 __ NumberOfOwnDescriptors(ecx, ebx);
3020 __ cmp(ecx, 0);
3021 __ j(equal, &done);
3022
danno@chromium.org40cb8782011-05-25 07:58:50 +00003023 __ LoadInstanceDescriptors(ebx, ebx);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003024 // ebx: descriptor array.
3025 // ecx: valid entries in the descriptor array.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003026 // Calculate the end of the descriptor array.
3027 STATIC_ASSERT(kSmiTag == 0);
3028 STATIC_ASSERT(kSmiTagSize == 1);
3029 STATIC_ASSERT(kPointerSize == 4);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003030 __ imul(ecx, ecx, DescriptorArray::kDescriptorSize);
3031 __ lea(ecx, Operand(ebx, ecx, times_2, DescriptorArray::kFirstOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003032 // Calculate location of the first key name.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003033 __ add(ebx, Immediate(DescriptorArray::kFirstOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003034 // Loop through all the keys in the descriptor array. If one of these is the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003035 // internalized string "valueOf" the result is false.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003036 __ jmp(&entry);
3037 __ bind(&loop);
3038 __ mov(edx, FieldOperand(ebx, 0));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003039 __ cmp(edx, isolate()->factory()->value_of_string());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003040 __ j(equal, if_false);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003041 __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003042 __ bind(&entry);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003043 __ cmp(ebx, ecx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003044 __ j(not_equal, &loop);
3045
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003046 __ bind(&done);
3047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003048 // Reload map as register ebx was used as temporary above.
3049 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3050
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003051 // Set the bit in the map to indicate that there is no local valueOf field.
3052 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
3053 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
3054
3055 __ bind(&skip_lookup);
3056
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003057 // If a valueOf property is not found on the object check that its
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003058 // prototype is the un-modified String prototype. If not result is false.
3059 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003060 __ JumpIfSmi(ecx, if_false);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003061 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003062 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003063 __ mov(edx,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003064 FieldOperand(edx, GlobalObject::kNativeContextOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003065 __ cmp(ecx,
3066 ContextOperand(edx,
3067 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003068 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003069 Split(equal, if_true, if_false, fall_through);
3070
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003071 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003072}
3073
3074
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003075void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3076 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003077 ASSERT(args->length() == 1);
3078
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003079 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003080
3081 Label materialize_true, materialize_false;
3082 Label* if_true = NULL;
3083 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003084 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003085 context()->PrepareTest(&materialize_true, &materialize_false,
3086 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003087
whesse@chromium.org7b260152011-06-20 15:33:18 +00003088 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003089 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003090 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003091 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003092
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003093 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003094}
3095
3096
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00003097void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3098 ZoneList<Expression*>* args = expr->arguments();
3099 ASSERT(args->length() == 1);
3100
3101 VisitForAccumulatorValue(args->at(0));
3102
3103 Label materialize_true, materialize_false;
3104 Label* if_true = NULL;
3105 Label* if_false = NULL;
3106 Label* fall_through = NULL;
3107 context()->PrepareTest(&materialize_true, &materialize_false,
3108 &if_true, &if_false, &fall_through);
3109
3110 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
3111 __ CheckMap(eax, map, if_false, DO_SMI_CHECK);
3112 __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x80000000));
3113 __ j(not_equal, if_false);
3114 __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x00000000));
3115 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3116 Split(equal, if_true, if_false, fall_through);
3117
3118 context()->Plug(if_true, if_false);
3119}
3120
3121
3122
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003123void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3124 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003125 ASSERT(args->length() == 1);
3126
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003127 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003128
3129 Label materialize_true, materialize_false;
3130 Label* if_true = NULL;
3131 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003132 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003133 context()->PrepareTest(&materialize_true, &materialize_false,
3134 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003135
whesse@chromium.org7b260152011-06-20 15:33:18 +00003136 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003137 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003138 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003139 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003140
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003141 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003142}
3143
3144
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003145void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3146 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003147 ASSERT(args->length() == 1);
3148
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003149 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003150
3151 Label materialize_true, materialize_false;
3152 Label* if_true = NULL;
3153 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003154 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003155 context()->PrepareTest(&materialize_true, &materialize_false,
3156 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003157
whesse@chromium.org7b260152011-06-20 15:33:18 +00003158 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003159 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003160 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003161 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003162
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003163 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003164}
3165
3166
3167
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003168void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
3169 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003170
3171 Label materialize_true, materialize_false;
3172 Label* if_true = NULL;
3173 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003174 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003175 context()->PrepareTest(&materialize_true, &materialize_false,
3176 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003177
3178 // Get the frame pointer for the calling frame.
3179 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3180
3181 // Skip the arguments adaptor frame if it exists.
3182 Label check_frame_marker;
3183 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
3184 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3185 __ j(not_equal, &check_frame_marker);
3186 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
3187
3188 // Check the marker in the calling frame.
3189 __ bind(&check_frame_marker);
3190 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
3191 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003192 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003193 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003194
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003195 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003196}
3197
3198
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003199void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3200 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003201 ASSERT(args->length() == 2);
3202
3203 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003204 VisitForStackValue(args->at(0));
3205 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003206
3207 Label materialize_true, materialize_false;
3208 Label* if_true = NULL;
3209 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003210 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003211 context()->PrepareTest(&materialize_true, &materialize_false,
3212 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003213
3214 __ pop(ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003215 __ cmp(eax, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003216 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003217 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003218
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003219 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003220}
3221
3222
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003223void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3224 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003225 ASSERT(args->length() == 1);
3226
3227 // ArgumentsAccessStub expects the key in edx and the formal
3228 // parameter count in eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003229 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003230 __ mov(edx, eax);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003231 __ Set(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003232 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
3233 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003234 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003235}
3236
3237
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003238void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
3239 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003240
3241 Label exit;
3242 // Get the number of formal parameters.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003243 __ Set(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003244
3245 // Check if the calling frame is an arguments adaptor frame.
3246 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3247 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
3248 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3249 __ j(not_equal, &exit);
3250
3251 // Arguments adaptor case: Read the arguments length from the
3252 // adaptor frame.
3253 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3254
3255 __ bind(&exit);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003256 __ AssertSmi(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003257 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003258}
3259
3260
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003261void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3262 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003263 ASSERT(args->length() == 1);
3264 Label done, null, function, non_function_constructor;
3265
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003266 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003267
3268 // If the object is a smi, we return null.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003269 __ JumpIfSmi(eax, &null);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003270
3271 // Check that the object is a JS object but take special care of JS
3272 // functions to make sure they have 'Function' as their class.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003273 // Assume that there are only two callable types, and one of them is at
3274 // either end of the type range for JS object types. Saves extra comparisons.
3275 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003276 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
3277 // Map is now in eax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003278 __ j(below, &null);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003279 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3280 FIRST_SPEC_OBJECT_TYPE + 1);
3281 __ j(equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003282
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003283 __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
3284 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3285 LAST_SPEC_OBJECT_TYPE - 1);
3286 __ j(equal, &function);
3287 // Assume that there is no larger type.
3288 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003289
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003290 // Check if the constructor in the map is a JS function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003291 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
3292 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3293 __ j(not_equal, &non_function_constructor);
3294
3295 // eax now contains the constructor function. Grab the
3296 // instance class name from there.
3297 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
3298 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
3299 __ jmp(&done);
3300
3301 // Functions have class 'Function'.
3302 __ bind(&function);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003303 __ mov(eax, isolate()->factory()->function_class_string());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003304 __ jmp(&done);
3305
3306 // Objects with a non-function constructor have class 'Object'.
3307 __ bind(&non_function_constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003308 __ mov(eax, isolate()->factory()->Object_string());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003309 __ jmp(&done);
3310
3311 // Non-JS objects have class null.
3312 __ bind(&null);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003313 __ mov(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003314
3315 // All done.
3316 __ bind(&done);
3317
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003318 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003319}
3320
3321
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003322void FullCodeGenerator::EmitLog(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003323 // Conditionally generate a log call.
3324 // Args:
3325 // 0 (literal string): The type of logging (corresponds to the flags).
3326 // This is used to determine whether or not to generate the log call.
3327 // 1 (string): Format string. Access the string at argument index 2
3328 // with '%2s' (see Logger::LogRuntime for all the formats).
3329 // 2 (array): Arguments to the format string.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003330 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003331 ASSERT_EQ(args->length(), 3);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003332 if (CodeGenerator::ShouldGenerateLog(isolate(), args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003333 VisitForStackValue(args->at(1));
3334 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003335 __ CallRuntime(Runtime::kLog, 2);
3336 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003337 // Finally, we're expected to leave a value on the top of the stack.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003339 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003340}
3341
3342
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003343void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003344 // Load the arguments on the stack and call the stub.
3345 SubStringStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003346 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003347 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003348 VisitForStackValue(args->at(0));
3349 VisitForStackValue(args->at(1));
3350 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003351 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003352 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003353}
3354
3355
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003356void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003357 // Load the arguments on the stack and call the stub.
3358 RegExpExecStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003359 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003360 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003361 VisitForStackValue(args->at(0));
3362 VisitForStackValue(args->at(1));
3363 VisitForStackValue(args->at(2));
3364 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003365 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003366 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003367}
3368
3369
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003370void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3371 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003372 ASSERT(args->length() == 1);
3373
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003374 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003375
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003376 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003377 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003378 __ JumpIfSmi(eax, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003379 // If the object is not a value type, return the object.
3380 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003381 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003382 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
3383
3384 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003385 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003386}
3387
3388
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003389void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3390 ZoneList<Expression*>* args = expr->arguments();
3391 ASSERT(args->length() == 2);
3392 ASSERT_NE(NULL, args->at(1)->AsLiteral());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003393 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003394
3395 VisitForAccumulatorValue(args->at(0)); // Load the object.
3396
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003397 Label runtime, done, not_date_object;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003398 Register object = eax;
3399 Register result = eax;
3400 Register scratch = ecx;
3401
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003402 __ JumpIfSmi(object, &not_date_object);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003403 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003404 __ j(not_equal, &not_date_object);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003405
3406 if (index->value() == 0) {
3407 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003408 __ jmp(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003409 } else {
3410 if (index->value() < JSDate::kFirstUncachedField) {
3411 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3412 __ mov(scratch, Operand::StaticVariable(stamp));
3413 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
3414 __ j(not_equal, &runtime, Label::kNear);
3415 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
3416 kPointerSize * index->value()));
3417 __ jmp(&done);
3418 }
3419 __ bind(&runtime);
3420 __ PrepareCallCFunction(2, scratch);
3421 __ mov(Operand(esp, 0), object);
3422 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
3423 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003424 __ jmp(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003425 }
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003426
3427 __ bind(&not_date_object);
3428 __ CallRuntime(Runtime::kThrowNotDateError, 0);
3429 __ bind(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003430 context()->Plug(result);
3431}
3432
3433
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003434void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3435 ZoneList<Expression*>* args = expr->arguments();
3436 ASSERT_EQ(3, args->length());
3437
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003438 Register string = eax;
3439 Register index = ebx;
3440 Register value = ecx;
3441
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003442 VisitForStackValue(args->at(1)); // index
3443 VisitForStackValue(args->at(2)); // value
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003444 VisitForAccumulatorValue(args->at(0)); // string
3445
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003446 __ pop(value);
3447 __ pop(index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003448
3449 if (FLAG_debug_code) {
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003450 __ test(value, Immediate(kSmiTagMask));
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003451 __ Check(zero, kNonSmiValue);
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003452 __ test(index, Immediate(kSmiTagMask));
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003453 __ Check(zero, kNonSmiValue);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003454 }
3455
3456 __ SmiUntag(value);
3457 __ SmiUntag(index);
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003458
3459 if (FLAG_debug_code) {
3460 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
3461 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
3462 }
3463
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003464 __ mov_b(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
3465 value);
3466 context()->Plug(string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003467}
3468
3469
3470void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3471 ZoneList<Expression*>* args = expr->arguments();
3472 ASSERT_EQ(3, args->length());
3473
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003474 Register string = eax;
3475 Register index = ebx;
3476 Register value = ecx;
3477
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003478 VisitForStackValue(args->at(1)); // index
3479 VisitForStackValue(args->at(2)); // value
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003480 VisitForAccumulatorValue(args->at(0)); // string
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003481 __ pop(value);
3482 __ pop(index);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003483
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003484 if (FLAG_debug_code) {
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003485 __ test(value, Immediate(kSmiTagMask));
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003486 __ Check(zero, kNonSmiValue);
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003487 __ test(index, Immediate(kSmiTagMask));
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003488 __ Check(zero, kNonSmiValue);
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003489 __ SmiUntag(index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003490 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003491 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
3492 __ SmiTag(index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003493 }
3494
3495 __ SmiUntag(value);
3496 // No need to untag a smi for two-byte addressing.
3497 __ mov_w(FieldOperand(string, index, times_1, SeqTwoByteString::kHeaderSize),
3498 value);
3499 context()->Plug(string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003500}
3501
3502
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003503void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003504 // Load the arguments on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003505 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003506 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003507 VisitForStackValue(args->at(0));
3508 VisitForStackValue(args->at(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003510 if (CpuFeatures::IsSupported(SSE2)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003511 MathPowStub stub(MathPowStub::ON_STACK);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003512 __ CallStub(&stub);
3513 } else {
3514 __ CallRuntime(Runtime::kMath_pow, 2);
3515 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003516 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003517}
3518
3519
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003520void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3521 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003522 ASSERT(args->length() == 2);
3523
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003524 VisitForStackValue(args->at(0)); // Load the object.
3525 VisitForAccumulatorValue(args->at(1)); // Load the value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003526 __ pop(ebx); // eax = value. ebx = object.
3527
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003528 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003529 // If the object is a smi, return the value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003530 __ JumpIfSmi(ebx, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003531
3532 // If the object is not a value type, return the value.
3533 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003534 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003535
3536 // Store the value.
3537 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003538
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003539 // Update the write barrier. Save the value as it will be
3540 // overwritten by the write barrier code and is needed afterward.
3541 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003542 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003543
3544 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003545 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003546}
3547
3548
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003549void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3550 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003551 ASSERT_EQ(args->length(), 1);
3552
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003553 // Load the argument into eax and call the stub.
3554 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003555
3556 NumberToStringStub stub;
3557 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003558 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003559}
3560
3561
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003562void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3563 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003564 ASSERT(args->length() == 1);
3565
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003566 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003567
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003568 Label done;
3569 StringCharFromCodeGenerator generator(eax, ebx);
3570 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003571 __ jmp(&done);
3572
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003573 NopRuntimeCallHelper call_helper;
3574 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003575
3576 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003577 context()->Plug(ebx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003578}
3579
3580
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003581void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3582 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003583 ASSERT(args->length() == 2);
3584
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003585 VisitForStackValue(args->at(0));
3586 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003587
3588 Register object = ebx;
3589 Register index = eax;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003590 Register result = edx;
3591
3592 __ pop(object);
3593
3594 Label need_conversion;
3595 Label index_out_of_range;
3596 Label done;
3597 StringCharCodeAtGenerator generator(object,
3598 index,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003599 result,
3600 &need_conversion,
3601 &need_conversion,
3602 &index_out_of_range,
3603 STRING_INDEX_IS_NUMBER);
3604 generator.GenerateFast(masm_);
3605 __ jmp(&done);
3606
3607 __ bind(&index_out_of_range);
3608 // When the index is out of range, the spec requires us to return
3609 // NaN.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610 __ Set(result, Immediate(isolate()->factory()->nan_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003611 __ jmp(&done);
3612
3613 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003614 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003615 // trigger conversion.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 __ Set(result, Immediate(isolate()->factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003617 __ jmp(&done);
3618
3619 NopRuntimeCallHelper call_helper;
3620 generator.GenerateSlow(masm_, call_helper);
3621
3622 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003623 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003624}
3625
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003626
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003627void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3628 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003629 ASSERT(args->length() == 2);
3630
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003631 VisitForStackValue(args->at(0));
3632 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003633
3634 Register object = ebx;
3635 Register index = eax;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003636 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003637 Register result = eax;
3638
3639 __ pop(object);
3640
3641 Label need_conversion;
3642 Label index_out_of_range;
3643 Label done;
3644 StringCharAtGenerator generator(object,
3645 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003646 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003647 result,
3648 &need_conversion,
3649 &need_conversion,
3650 &index_out_of_range,
3651 STRING_INDEX_IS_NUMBER);
3652 generator.GenerateFast(masm_);
3653 __ jmp(&done);
3654
3655 __ bind(&index_out_of_range);
3656 // When the index is out of range, the spec requires us to return
3657 // the empty string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658 __ Set(result, Immediate(isolate()->factory()->empty_string()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003659 __ jmp(&done);
3660
3661 __ bind(&need_conversion);
3662 // Move smi zero into the result register, which will trigger
3663 // conversion.
3664 __ Set(result, Immediate(Smi::FromInt(0)));
3665 __ jmp(&done);
3666
3667 NopRuntimeCallHelper call_helper;
3668 generator.GenerateSlow(masm_, call_helper);
3669
3670 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003671 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003672}
3673
3674
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003675void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3676 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003677 ASSERT_EQ(2, args->length());
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +00003678 VisitForStackValue(args->at(0));
3679 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003680
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +00003681 __ pop(edx);
3682 StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
3683 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003684 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003685}
3686
3687
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003688void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3689 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003690 ASSERT_EQ(2, args->length());
3691
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003692 VisitForStackValue(args->at(0));
3693 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003694
3695 StringCompareStub stub;
3696 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003697 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003698}
3699
3700
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003701void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003702 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003703 ZoneList<Expression*>* args = expr->arguments();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003704 ASSERT(args->length() == 1);
3705 VisitForStackValue(args->at(0));
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003706 __ CallRuntime(Runtime::kMath_log, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003707 context()->Plug(eax);
3708}
3709
3710
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003711void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003712 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003713 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003714 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003715 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003716 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003717 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003718}
3719
3720
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003721void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3722 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003723 ASSERT(args->length() >= 2);
3724
danno@chromium.org160a7b02011-04-18 15:51:38 +00003725 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3726 for (int i = 0; i < arg_count + 1; ++i) {
3727 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003728 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003729 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003730
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003731 Label runtime, done;
3732 // Check for non-function argument (including proxy).
3733 __ JumpIfSmi(eax, &runtime);
3734 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3735 __ j(not_equal, &runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003736
danno@chromium.org160a7b02011-04-18 15:51:38 +00003737 // InvokeFunction requires the function in edi. Move it in there.
3738 __ mov(edi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003739 ParameterCount count(arg_count);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003740 __ InvokeFunction(edi, count, CALL_FUNCTION, NullCallWrapper());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003741 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003742 __ jmp(&done);
3743
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003744 __ bind(&runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003745 __ push(eax);
3746 __ CallRuntime(Runtime::kCall, args->length());
3747 __ bind(&done);
3748
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003749 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003750}
3751
3752
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003753void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003754 // Load the arguments on the stack and call the stub.
3755 RegExpConstructResultStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003756 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003757 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003758 VisitForStackValue(args->at(0));
3759 VisitForStackValue(args->at(1));
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +00003760 VisitForAccumulatorValue(args->at(2));
3761 __ pop(ebx);
3762 __ pop(ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003763 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003764 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003765}
3766
3767
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003768void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3769 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003770 ASSERT_EQ(2, args->length());
3771
3772 ASSERT_NE(NULL, args->at(0)->AsLiteral());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003773 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003774
3775 Handle<FixedArray> jsfunction_result_caches(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003776 isolate()->native_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003777 if (jsfunction_result_caches->length() <= cache_id) {
danno@chromium.org59400602013-08-13 17:09:37 +00003778 __ Abort(kAttemptToUseUndefinedCache);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003779 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003780 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003781 return;
3782 }
3783
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003784 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003785
3786 Register key = eax;
3787 Register cache = ebx;
3788 Register tmp = ecx;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003789 __ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003790 __ mov(cache,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003791 FieldOperand(cache, GlobalObject::kNativeContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003792 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003793 __ mov(cache,
3794 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3795
3796 Label done, not_found;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003797 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003798 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
machenbach@chromium.org0a730362014-02-05 03:04:56 +00003799 // tmp now holds finger offset as a smi.
3800 __ cmp(key, FixedArrayElementOperand(cache, tmp));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003801 __ j(not_equal, &not_found);
3802
machenbach@chromium.org0a730362014-02-05 03:04:56 +00003803 __ mov(eax, FixedArrayElementOperand(cache, tmp, 1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003804 __ jmp(&done);
3805
3806 __ bind(&not_found);
3807 // Call runtime to perform the lookup.
3808 __ push(cache);
3809 __ push(key);
3810 __ CallRuntime(Runtime::kGetFromCache, 2);
3811
3812 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003813 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003814}
3815
3816
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003817void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3818 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003819 ASSERT(args->length() == 1);
3820
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003821 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003822
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003823 __ AssertString(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003824
3825 Label materialize_true, materialize_false;
3826 Label* if_true = NULL;
3827 Label* if_false = NULL;
3828 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003829 context()->PrepareTest(&materialize_true, &materialize_false,
3830 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003831
3832 __ test(FieldOperand(eax, String::kHashFieldOffset),
3833 Immediate(String::kContainsCachedArrayIndexMask));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003834 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003835 Split(zero, if_true, if_false, fall_through);
3836
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003837 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003838}
3839
3840
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003841void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3842 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003843 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003844 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003845
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003846 __ AssertString(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003847
3848 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3849 __ IndexFromHash(eax, eax);
3850
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003851 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003852}
3853
3854
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003855void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003856 Label bailout, done, one_char_separator, long_separator,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003857 non_trivial_array, not_size_one_array, loop,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003858 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003859
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003860 ZoneList<Expression*>* args = expr->arguments();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003861 ASSERT(args->length() == 2);
3862 // We will leave the separator on the stack until the end of the function.
3863 VisitForStackValue(args->at(1));
3864 // Load this to eax (= array)
3865 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003866 // All aliases of the same register have disjoint lifetimes.
3867 Register array = eax;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003868 Register elements = no_reg; // Will be eax.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003869
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003870 Register index = edx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003871
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003872 Register string_length = ecx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003873
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003874 Register string = esi;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003875
3876 Register scratch = ebx;
3877
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003878 Register array_length = edi;
3879 Register result_pos = no_reg; // Will be edi.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003880
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003881 // Separator operand is already pushed.
3882 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3883 Operand result_operand = Operand(esp, 1 * kPointerSize);
3884 Operand array_length_operand = Operand(esp, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003885 __ sub(esp, Immediate(2 * kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003886 __ cld();
3887 // Check that the array is a JSArray
whesse@chromium.org7b260152011-06-20 15:33:18 +00003888 __ JumpIfSmi(array, &bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003889 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3890 __ j(not_equal, &bailout);
3891
3892 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003893 __ CheckFastElements(scratch, &bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003894
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003895 // If the array has length zero, return the empty string.
3896 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003897 __ SmiUntag(array_length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003898 __ j(not_zero, &non_trivial_array);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003899 __ mov(result_operand, isolate()->factory()->empty_string());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003900 __ jmp(&done);
3901
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003902 // Save the array length.
3903 __ bind(&non_trivial_array);
3904 __ mov(array_length_operand, array_length);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003905
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003906 // Save the FixedArray containing array's elements.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003907 // End of array's live range.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003908 elements = array;
3909 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003910 array = no_reg;
3911
3912
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003913 // Check that all array elements are sequential ASCII strings, and
3914 // accumulate the sum of their lengths, as a smi-encoded value.
3915 __ Set(index, Immediate(0));
3916 __ Set(string_length, Immediate(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003917 // Loop condition: while (index < length).
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003918 // Live loop registers: index, array_length, string,
3919 // scratch, string_length, elements.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003920 if (generate_debug_code_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003921 __ cmp(index, array_length);
danno@chromium.org59400602013-08-13 17:09:37 +00003922 __ Assert(less, kNoEmptyArraysHereInEmitFastAsciiArrayJoin);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003923 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003924 __ bind(&loop);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003925 __ mov(string, FieldOperand(elements,
3926 index,
3927 times_pointer_size,
3928 FixedArray::kHeaderSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003929 __ JumpIfSmi(string, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003930 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3931 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3932 __ and_(scratch, Immediate(
3933 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003934 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003935 __ j(not_equal, &bailout);
3936 __ add(string_length,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003937 FieldOperand(string, SeqOneByteString::kLengthOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003938 __ j(overflow, &bailout);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003939 __ add(index, Immediate(1));
3940 __ cmp(index, array_length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003941 __ j(less, &loop);
3942
3943 // If array_length is 1, return elements[0], a string.
3944 __ cmp(array_length, 1);
3945 __ j(not_equal, &not_size_one_array);
3946 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3947 __ mov(result_operand, scratch);
3948 __ jmp(&done);
3949
3950 __ bind(&not_size_one_array);
3951
3952 // End of array_length live range.
3953 result_pos = array_length;
3954 array_length = no_reg;
3955
3956 // Live registers:
3957 // string_length: Sum of string lengths, as a smi.
3958 // elements: FixedArray of strings.
3959
3960 // Check that the separator is a flat ASCII string.
3961 __ mov(string, separator_operand);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003962 __ JumpIfSmi(string, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003963 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3964 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003965 __ and_(scratch, Immediate(
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00003966 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00003967 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003968 __ j(not_equal, &bailout);
3969
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003970 // Add (separator length times array_length) - separator length
3971 // to string_length.
3972 __ mov(scratch, separator_operand);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003973 __ mov(scratch, FieldOperand(scratch, SeqOneByteString::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003974 __ sub(string_length, scratch); // May be negative, temporarily.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003975 __ imul(scratch, array_length_operand);
3976 __ j(overflow, &bailout);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003977 __ add(string_length, scratch);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003978 __ j(overflow, &bailout);
3979
3980 __ shr(string_length, 1);
3981 // Live registers and stack values:
3982 // string_length
3983 // elements
3984 __ AllocateAsciiString(result_pos, string_length, scratch,
3985 index, string, &bailout);
3986 __ mov(result_operand, result_pos);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003987 __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003988
3989
3990 __ mov(string, separator_operand);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003991 __ cmp(FieldOperand(string, SeqOneByteString::kLengthOffset),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003992 Immediate(Smi::FromInt(1)));
3993 __ j(equal, &one_char_separator);
3994 __ j(greater, &long_separator);
3995
3996
3997 // Empty separator case
3998 __ mov(index, Immediate(0));
3999 __ jmp(&loop_1_condition);
4000 // Loop condition: while (index < length).
4001 __ bind(&loop_1);
4002 // Each iteration of the loop concatenates one string to the result.
4003 // Live values in registers:
4004 // index: which element of the elements array we are adding to the result.
4005 // result_pos: the position to which we are currently copying characters.
4006 // elements: the FixedArray of strings we are joining.
4007
4008 // Get string = array[index].
4009 __ mov(string, FieldOperand(elements, index,
4010 times_pointer_size,
4011 FixedArray::kHeaderSize));
4012 __ mov(string_length,
4013 FieldOperand(string, String::kLengthOffset));
4014 __ shr(string_length, 1);
4015 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004016 FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004017 __ CopyBytes(string, result_pos, string_length, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004018 __ add(index, Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004019 __ bind(&loop_1_condition);
4020 __ cmp(index, array_length_operand);
4021 __ j(less, &loop_1); // End while (index < length).
4022 __ jmp(&done);
4023
4024
4025
4026 // One-character separator case
4027 __ bind(&one_char_separator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004028 // Replace separator with its ASCII character value.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004029 __ mov_b(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004030 __ mov_b(separator_operand, scratch);
4031
4032 __ Set(index, Immediate(0));
4033 // Jump into the loop after the code that copies the separator, so the first
4034 // element is not preceded by a separator
4035 __ jmp(&loop_2_entry);
4036 // Loop condition: while (index < length).
4037 __ bind(&loop_2);
4038 // Each iteration of the loop concatenates one string to the result.
4039 // Live values in registers:
4040 // index: which element of the elements array we are adding to the result.
4041 // result_pos: the position to which we are currently copying characters.
4042
4043 // Copy the separator character to the result.
4044 __ mov_b(scratch, separator_operand);
4045 __ mov_b(Operand(result_pos, 0), scratch);
4046 __ inc(result_pos);
4047
4048 __ bind(&loop_2_entry);
4049 // Get string = array[index].
4050 __ mov(string, FieldOperand(elements, index,
4051 times_pointer_size,
4052 FixedArray::kHeaderSize));
4053 __ mov(string_length,
4054 FieldOperand(string, String::kLengthOffset));
4055 __ shr(string_length, 1);
4056 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004057 FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004058 __ CopyBytes(string, result_pos, string_length, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004059 __ add(index, Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004060
4061 __ cmp(index, array_length_operand);
4062 __ j(less, &loop_2); // End while (index < length).
4063 __ jmp(&done);
4064
4065
4066 // Long separator case (separator is more than one character).
4067 __ bind(&long_separator);
4068
4069 __ Set(index, Immediate(0));
4070 // Jump into the loop after the code that copies the separator, so the first
4071 // element is not preceded by a separator
4072 __ jmp(&loop_3_entry);
4073 // Loop condition: while (index < length).
4074 __ bind(&loop_3);
4075 // Each iteration of the loop concatenates one string to the result.
4076 // Live values in registers:
4077 // index: which element of the elements array we are adding to the result.
4078 // result_pos: the position to which we are currently copying characters.
4079
4080 // Copy the separator to the result.
4081 __ mov(string, separator_operand);
4082 __ mov(string_length,
4083 FieldOperand(string, String::kLengthOffset));
4084 __ shr(string_length, 1);
4085 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004086 FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004087 __ CopyBytes(string, result_pos, string_length, scratch);
4088
4089 __ bind(&loop_3_entry);
4090 // Get string = array[index].
4091 __ mov(string, FieldOperand(elements, index,
4092 times_pointer_size,
4093 FixedArray::kHeaderSize));
4094 __ mov(string_length,
4095 FieldOperand(string, String::kLengthOffset));
4096 __ shr(string_length, 1);
4097 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004098 FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004099 __ CopyBytes(string, result_pos, string_length, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004100 __ add(index, Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004101
4102 __ cmp(index, array_length_operand);
4103 __ j(less, &loop_3); // End while (index < length).
4104 __ jmp(&done);
4105
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004106
4107 __ bind(&bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004108 __ mov(result_operand, isolate()->factory()->undefined_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004109 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004110 __ mov(eax, result_operand);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004111 // Drop temp values from the stack, and restore context register.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004112 __ add(esp, Immediate(3 * kPointerSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004113
4114 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4115 context()->Plug(eax);
4116}
4117
4118
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004119void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004120 Handle<String> name = expr->name();
4121 if (name->length() > 0 && name->Get(0) == '_') {
4122 Comment cmnt(masm_, "[ InlineRuntimeCall");
4123 EmitInlineRuntimeCall(expr);
4124 return;
4125 }
4126
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004127 Comment cmnt(masm_, "[ CallRuntime");
4128 ZoneList<Expression*>* args = expr->arguments();
4129
4130 if (expr->is_jsruntime()) {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004131 // Push the builtins object as receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004132 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004133 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004134
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004135 // Load the function from the receiver.
4136 __ mov(edx, Operand(esp, 0));
4137 __ mov(ecx, Immediate(expr->name()));
4138 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004139
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004140 // Push the target function under the receiver.
4141 __ push(Operand(esp, 0));
4142 __ mov(Operand(esp, kPointerSize), eax);
4143
4144 // Code common for calls using the IC.
4145 ZoneList<Expression*>* args = expr->arguments();
4146 int arg_count = args->length();
4147 for (int i = 0; i < arg_count; i++) {
4148 VisitForStackValue(args->at(i));
4149 }
4150
4151 // Record source position of the IC call.
4152 SetSourcePosition(expr->position());
4153 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS);
4154 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
4155 __ CallStub(&stub);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004156 // Restore context register.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004157 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004158 context()->DropAndPlug(1, eax);
4159
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004160 } else {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004161 // Push the arguments ("left-to-right").
4162 int arg_count = args->length();
4163 for (int i = 0; i < arg_count; i++) {
4164 VisitForStackValue(args->at(i));
4165 }
4166
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004167 // Call the C runtime function.
4168 __ CallRuntime(expr->function(), arg_count);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004169
4170 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004172}
4173
4174
4175void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4176 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004177 case Token::DELETE: {
4178 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004179 Property* property = expr->expression()->AsProperty();
4180 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004181
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004182 if (property != NULL) {
4183 VisitForStackValue(property->obj());
4184 VisitForStackValue(property->key());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004185 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
4186 ? kNonStrictMode : kStrictMode;
4187 __ push(Immediate(Smi::FromInt(strict_mode_flag)));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004188 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004189 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004190 } else if (proxy != NULL) {
4191 Variable* var = proxy->var();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004192 // Delete of an unqualified identifier is disallowed in strict mode
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004193 // but "delete this" is allowed.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004194 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004195 if (var->IsUnallocated()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004196 __ push(GlobalObjectOperand());
4197 __ push(Immediate(var->name()));
4198 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
4199 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4200 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004201 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
4202 // Result of deleting non-global variables is false. 'this' is
4203 // not really a variable, though we implement it as one. The
4204 // subexpression does not have side effects.
4205 context()->Plug(var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004206 } else {
4207 // Non-global variable. Call the runtime to try to delete from the
4208 // context where the variable was introduced.
4209 __ push(context_register());
4210 __ push(Immediate(var->name()));
4211 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
4212 context()->Plug(eax);
4213 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004214 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004215 // Result of deleting non-property, non-variable reference is true.
4216 // The subexpression may have side effects.
4217 VisitForEffect(expr->expression());
4218 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004219 }
4220 break;
4221 }
4222
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004223 case Token::VOID: {
4224 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4225 VisitForEffect(expr->expression());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004226 context()->Plug(isolate()->factory()->undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004227 break;
4228 }
4229
4230 case Token::NOT: {
4231 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004232 if (context()->IsEffect()) {
4233 // Unary NOT has no side effects so it's only necessary to visit the
4234 // subexpression. Match the optimizing compiler by not branching.
4235 VisitForEffect(expr->expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004236 } else if (context()->IsTest()) {
4237 const TestContext* test = TestContext::cast(context());
4238 // The labels are swapped for the recursive call.
4239 VisitForControl(expr->expression(),
4240 test->false_label(),
4241 test->true_label(),
4242 test->fall_through());
4243 context()->Plug(test->true_label(), test->false_label());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004244 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004245 // We handle value contexts explicitly rather than simply visiting
4246 // for control and plugging the control flow into the context,
4247 // because we need to prepare a pair of extra administrative AST ids
4248 // for the optimizing compiler.
4249 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
4250 Label materialize_true, materialize_false, done;
4251 VisitForControl(expr->expression(),
4252 &materialize_false,
4253 &materialize_true,
4254 &materialize_true);
4255 __ bind(&materialize_true);
4256 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4257 if (context()->IsAccumulatorValue()) {
4258 __ mov(eax, isolate()->factory()->true_value());
4259 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004260 __ Push(isolate()->factory()->true_value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004261 }
4262 __ jmp(&done, Label::kNear);
4263 __ bind(&materialize_false);
4264 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4265 if (context()->IsAccumulatorValue()) {
4266 __ mov(eax, isolate()->factory()->false_value());
4267 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004268 __ Push(isolate()->factory()->false_value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004269 }
4270 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004271 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004272 break;
4273 }
4274
4275 case Token::TYPEOF: {
4276 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004277 { StackValueContext context(this);
4278 VisitForTypeofValue(expr->expression());
4279 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004280 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004281 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004282 break;
4283 }
4284
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004285 default:
4286 UNREACHABLE();
4287 }
4288}
4289
4290
4291void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
4292 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004293 SetSourcePosition(expr->position());
4294
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004295 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
4296 // as the left-hand side.
4297 if (!expr->expression()->IsValidLeftHandSide()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004298 VisitForEffect(expr->expression());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004299 return;
4300 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004301
4302 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00004303 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004304 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
4305 LhsKind assign_type = VARIABLE;
4306 Property* prop = expr->expression()->AsProperty();
4307 // In case of a property we use the uninitialized expression context
4308 // of the key to detect a named property.
4309 if (prop != NULL) {
4310 assign_type =
4311 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
4312 }
4313
4314 // Evaluate expression and get value.
4315 if (assign_type == VARIABLE) {
4316 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004317 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00004318 EmitVariableLoad(expr->expression()->AsVariableProxy());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004319 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004320 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004321 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004322 __ push(Immediate(Smi::FromInt(0)));
4323 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004324 if (assign_type == NAMED_PROPERTY) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004325 // Put the object both on the stack and in edx.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004326 VisitForAccumulatorValue(prop->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00004327 __ push(eax);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004328 __ mov(edx, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004329 EmitNamedPropertyLoad(prop);
4330 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004331 VisitForStackValue(prop->obj());
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004332 VisitForStackValue(prop->key());
4333 __ mov(edx, Operand(esp, kPointerSize)); // Object.
4334 __ mov(ecx, Operand(esp, 0)); // Key.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004335 EmitKeyedPropertyLoad(prop);
4336 }
4337 }
4338
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004339 // We need a second deoptimization point after loading the value
4340 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004341 if (assign_type == VARIABLE) {
4342 PrepareForBailout(expr->expression(), TOS_REG);
4343 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004344 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004345 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004346
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004347 // Inline smi case if we are in a loop.
4348 Label done, stub_call;
4349 JumpPatchSite patch_site(masm_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004350 if (ShouldInlineSmiCase(expr->op())) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004351 Label slow;
4352 patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
4353
4354 // Save result for postfix expressions.
4355 if (expr->is_postfix()) {
4356 if (!context()->IsEffect()) {
4357 // Save the result on the stack. If we have a named or keyed property
4358 // we store the result under the receiver that is currently on top
4359 // of the stack.
4360 switch (assign_type) {
4361 case VARIABLE:
4362 __ push(eax);
4363 break;
4364 case NAMED_PROPERTY:
4365 __ mov(Operand(esp, kPointerSize), eax);
4366 break;
4367 case KEYED_PROPERTY:
4368 __ mov(Operand(esp, 2 * kPointerSize), eax);
4369 break;
4370 }
4371 }
4372 }
4373
4374 if (expr->op() == Token::INC) {
4375 __ add(eax, Immediate(Smi::FromInt(1)));
4376 } else {
4377 __ sub(eax, Immediate(Smi::FromInt(1)));
4378 }
4379 __ j(no_overflow, &done, Label::kNear);
4380 // Call stub. Undo operation first.
4381 if (expr->op() == Token::INC) {
4382 __ sub(eax, Immediate(Smi::FromInt(1)));
4383 } else {
4384 __ add(eax, Immediate(Smi::FromInt(1)));
4385 }
4386 __ jmp(&stub_call, Label::kNear);
4387 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004388 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +00004389 ToNumberStub convert_stub;
4390 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004391
4392 // Save result for postfix expressions.
4393 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004394 if (!context()->IsEffect()) {
4395 // Save the result on the stack. If we have a named or keyed property
4396 // we store the result under the receiver that is currently on top
4397 // of the stack.
4398 switch (assign_type) {
4399 case VARIABLE:
4400 __ push(eax);
4401 break;
4402 case NAMED_PROPERTY:
4403 __ mov(Operand(esp, kPointerSize), eax);
4404 break;
4405 case KEYED_PROPERTY:
4406 __ mov(Operand(esp, 2 * kPointerSize), eax);
4407 break;
4408 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004409 }
4410 }
4411
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004412 // Record position before stub call.
4413 SetSourcePosition(expr->position());
4414
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004415 // Call stub for +1/-1.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004416 __ bind(&stub_call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004417 __ mov(edx, eax);
4418 __ mov(eax, Immediate(Smi::FromInt(1)));
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00004419 BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE);
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00004420 CallIC(stub.GetCode(isolate()), expr->CountBinOpFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004421 patch_site.EmitPatchInfo();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004422 __ bind(&done);
4423
4424 // Store the value returned in eax.
4425 switch (assign_type) {
4426 case VARIABLE:
4427 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004428 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004429 { EffectContext context(this);
4430 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4431 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004432 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4433 context.Plug(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004434 }
4435 // For all contexts except EffectContext We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004436 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004437 if (!context()->IsEffect()) {
4438 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004439 }
4440 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004441 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004442 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004443 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004444 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4445 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004446 }
4447 break;
4448 case NAMED_PROPERTY: {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004449 __ mov(ecx, prop->key()->AsLiteral()->value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004450 __ pop(edx);
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00004451 CallStoreIC(expr->CountStoreFeedbackId());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004452 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004453 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004454 if (!context()->IsEffect()) {
4455 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004456 }
4457 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004458 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004459 }
4460 break;
4461 }
4462 case KEYED_PROPERTY: {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004463 __ pop(ecx);
4464 __ pop(edx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004465 Handle<Code> ic = is_classic_mode()
4466 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4467 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00004468 CallIC(ic, expr->CountStoreFeedbackId());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004469 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004470 if (expr->is_postfix()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004471 // Result is on the stack
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004472 if (!context()->IsEffect()) {
4473 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004474 }
4475 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004476 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004477 }
4478 break;
4479 }
4480 }
4481}
4482
4483
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004484void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004485 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004486 ASSERT(!context()->IsEffect());
4487 ASSERT(!context()->IsTest());
4488
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004489 if (proxy != NULL && proxy->var()->IsUnallocated()) {
mstarzinger@chromium.org1e71c4d2014-02-13 10:16:41 +00004490 Comment cmnt(masm_, "[ Global variable");
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004491 __ mov(edx, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004492 __ mov(ecx, Immediate(proxy->name()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004493 // Use a regular load, not a contextual load, to avoid a reference
4494 // error.
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00004495 CallLoadIC(NOT_CONTEXTUAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004496 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004497 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004498 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
mstarzinger@chromium.org1e71c4d2014-02-13 10:16:41 +00004499 Comment cmnt(masm_, "[ Lookup slot");
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004500 Label done, slow;
4501
4502 // Generate code for loading from variables potentially shadowed
4503 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004504 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004505
4506 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004507 __ push(esi);
4508 __ push(Immediate(proxy->name()));
4509 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004510 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004511 __ bind(&done);
4512
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004513 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004514 } else {
4515 // This expression cannot throw a reference error at the top level.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004516 VisitInDuplicateContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004517 }
4518}
4519
4520
ager@chromium.org04921a82011-06-27 13:21:41 +00004521void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004522 Expression* sub_expr,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004523 Handle<String> check) {
4524 Label materialize_true, materialize_false;
4525 Label* if_true = NULL;
4526 Label* if_false = NULL;
4527 Label* fall_through = NULL;
4528 context()->PrepareTest(&materialize_true, &materialize_false,
4529 &if_true, &if_false, &fall_through);
4530
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004531 { AccumulatorValueContext context(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004532 VisitForTypeofValue(sub_expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004533 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004534 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004535
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004536 if (check->Equals(isolate()->heap()->number_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004537 __ JumpIfSmi(eax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004538 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004539 isolate()->factory()->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004540 Split(equal, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004541 } else if (check->Equals(isolate()->heap()->string_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004542 __ JumpIfSmi(eax, if_false);
4543 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4544 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004545 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004546 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4547 1 << Map::kIsUndetectable);
4548 Split(zero, if_true, if_false, fall_through);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004549 } else if (check->Equals(isolate()->heap()->symbol_string())) {
4550 __ JumpIfSmi(eax, if_false);
4551 __ CmpObjectType(eax, SYMBOL_TYPE, edx);
4552 Split(equal, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004553 } else if (check->Equals(isolate()->heap()->boolean_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004555 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004556 __ cmp(eax, isolate()->factory()->false_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004557 Split(equal, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004558 } else if (FLAG_harmony_typeof &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004559 check->Equals(isolate()->heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004560 __ cmp(eax, isolate()->factory()->null_value());
4561 Split(equal, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004562 } else if (check->Equals(isolate()->heap()->undefined_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004563 __ cmp(eax, isolate()->factory()->undefined_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004564 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004565 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004566 // Check for undetectable objects => true.
4567 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4568 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4569 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4570 Split(not_zero, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004571 } else if (check->Equals(isolate()->heap()->function_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004572 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004573 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4574 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
4575 __ j(equal, if_true);
4576 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
4577 Split(equal, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004578 } else if (check->Equals(isolate()->heap()->object_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004579 __ JumpIfSmi(eax, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004580 if (!FLAG_harmony_typeof) {
4581 __ cmp(eax, isolate()->factory()->null_value());
4582 __ j(equal, if_true);
4583 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004584 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004585 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004586 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4587 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004588 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004589 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4590 1 << Map::kIsUndetectable);
4591 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004592 } else {
4593 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004594 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004595 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004596}
4597
4598
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004599void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4600 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004601 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004602
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004603 // First we try a fast inlined version of the compare when one of
4604 // the operands is a literal.
4605 if (TryLiteralCompare(expr)) return;
4606
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004607 // Always perform the comparison for its control flow. Pack the result
4608 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004609 Label materialize_true, materialize_false;
4610 Label* if_true = NULL;
4611 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004612 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004613 context()->PrepareTest(&materialize_true, &materialize_false,
4614 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004615
ager@chromium.org04921a82011-06-27 13:21:41 +00004616 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004617 VisitForStackValue(expr->left());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004618 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004619 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004620 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004621 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004622 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004623 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004624 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004625 break;
4626
4627 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004628 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004629 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004630 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004631 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004632 __ test(eax, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004633 // The stub returns 0 for true.
4634 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004635 break;
4636 }
4637
4638 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004639 VisitForAccumulatorValue(expr->right());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004640 Condition cc = CompareIC::ComputeCondition(op);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004641 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004642
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004643 bool inline_smi_code = ShouldInlineSmiCase(op);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004644 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004645 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004646 Label slow_case;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004647 __ mov(ecx, edx);
4648 __ or_(ecx, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004649 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004650 __ cmp(edx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004651 Split(cc, if_true, if_false, NULL);
4652 __ bind(&slow_case);
4653 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004654
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004655 // Record position and call the compare IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004656 SetSourcePosition(expr->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004657 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00004658 CallIC(ic, expr->CompareOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004659 patch_site.EmitPatchInfo();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004660
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004661 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004662 __ test(eax, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004663 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004664 }
4665 }
4666
4667 // Convert the result of the comparison into one expected for this
4668 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004669 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004670}
4671
4672
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004673void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4674 Expression* sub_expr,
4675 NilValue nil) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004676 Label materialize_true, materialize_false;
4677 Label* if_true = NULL;
4678 Label* if_false = NULL;
4679 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004680 context()->PrepareTest(&materialize_true, &materialize_false,
4681 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004682
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004683 VisitForAccumulatorValue(sub_expr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004684 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004685
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004686 Handle<Object> nil_value = nil == kNullValue
4687 ? isolate()->factory()->null_value()
4688 : isolate()->factory()->undefined_value();
ulan@chromium.org837a67e2013-06-11 15:39:48 +00004689 if (expr->op() == Token::EQ_STRICT) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004690 __ cmp(eax, nil_value);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004691 Split(equal, if_true, if_false, fall_through);
4692 } else {
ulan@chromium.org837a67e2013-06-11 15:39:48 +00004693 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
machenbach@chromium.orgb7234fa2014-02-12 08:13:07 +00004694 CallIC(ic, expr->CompareOperationFeedbackId());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004695 __ test(eax, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004696 Split(not_zero, if_true, if_false, fall_through);
4697 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004698 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004699}
4700
4701
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004702void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4703 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004704 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004705}
4706
4707
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004708Register FullCodeGenerator::result_register() {
4709 return eax;
4710}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004711
4712
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004713Register FullCodeGenerator::context_register() {
4714 return esi;
4715}
4716
4717
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004718void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4719 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4720 __ mov(Operand(ebp, frame_offset), value);
4721}
4722
4723
4724void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004725 __ mov(dst, ContextOperand(esi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004726}
4727
4728
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004729void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004730 Scope* declaration_scope = scope()->DeclarationScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004731 if (declaration_scope->is_global_scope() ||
4732 declaration_scope->is_module_scope()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004733 // Contexts nested in the native context have a canonical empty function
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004734 // as their closure, not the anonymous closure containing the global
4735 // code. Pass a smi sentinel and let the runtime look up the empty
4736 // function.
4737 __ push(Immediate(Smi::FromInt(0)));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004738 } else if (declaration_scope->is_eval_scope()) {
4739 // Contexts nested inside eval code have the same closure as the context
4740 // calling eval, not the anonymous closure containing the eval code.
4741 // Fetch it from the context.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004742 __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
4743 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004744 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004745 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4746 }
4747}
4748
4749
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004750// ----------------------------------------------------------------------------
4751// Non-local control flow support.
4752
4753void FullCodeGenerator::EnterFinallyBlock() {
4754 // Cook return address on top of stack (smi encoded Code* delta)
4755 ASSERT(!result_register().is(edx));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004756 __ pop(edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004757 __ sub(edx, Immediate(masm_->CodeObject()));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00004758 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
4759 STATIC_ASSERT(kSmiTag == 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004760 __ SmiTag(edx);
4761 __ push(edx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004762
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004763 // Store result register while executing finally block.
4764 __ push(result_register());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004765
4766 // Store pending message while executing finally block.
4767 ExternalReference pending_message_obj =
4768 ExternalReference::address_of_pending_message_obj(isolate());
4769 __ mov(edx, Operand::StaticVariable(pending_message_obj));
4770 __ push(edx);
4771
4772 ExternalReference has_pending_message =
4773 ExternalReference::address_of_has_pending_message(isolate());
4774 __ mov(edx, Operand::StaticVariable(has_pending_message));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004775 __ SmiTag(edx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004776 __ push(edx);
4777
4778 ExternalReference pending_message_script =
4779 ExternalReference::address_of_pending_message_script(isolate());
4780 __ mov(edx, Operand::StaticVariable(pending_message_script));
4781 __ push(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004782}
4783
4784
4785void FullCodeGenerator::ExitFinallyBlock() {
4786 ASSERT(!result_register().is(edx));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004787 // Restore pending message from stack.
4788 __ pop(edx);
4789 ExternalReference pending_message_script =
4790 ExternalReference::address_of_pending_message_script(isolate());
4791 __ mov(Operand::StaticVariable(pending_message_script), edx);
4792
4793 __ pop(edx);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004794 __ SmiUntag(edx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004795 ExternalReference has_pending_message =
4796 ExternalReference::address_of_has_pending_message(isolate());
4797 __ mov(Operand::StaticVariable(has_pending_message), edx);
4798
4799 __ pop(edx);
4800 ExternalReference pending_message_obj =
4801 ExternalReference::address_of_pending_message_obj(isolate());
4802 __ mov(Operand::StaticVariable(pending_message_obj), edx);
4803
4804 // Restore result register from stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004805 __ pop(result_register());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004806
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004807 // Uncook return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004808 __ pop(edx);
4809 __ SmiUntag(edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004810 __ add(edx, Immediate(masm_->CodeObject()));
4811 __ jmp(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004812}
4813
4814
4815#undef __
4816
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004817#define __ ACCESS_MASM(masm())
4818
4819FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4820 int* stack_depth,
4821 int* context_length) {
4822 // The macros used here must preserve the result register.
4823
4824 // Because the handler block contains the context of the finally
4825 // code, we can restore it directly from there for the finally code
4826 // rather than iteratively unwinding contexts via their previous
4827 // links.
4828 __ Drop(*stack_depth); // Down to the handler block.
4829 if (*context_length > 0) {
4830 // Restore the context to its dedicated register and the stack.
4831 __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
4832 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
4833 }
4834 __ PopTryHandler();
4835 __ call(finally_entry_);
4836
4837 *stack_depth = 0;
4838 *context_length = 0;
4839 return previous_;
4840}
4841
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004842#undef __
4843
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004844
4845static const byte kJnsInstruction = 0x79;
4846static const byte kJnsOffset = 0x11;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004847static const byte kNopByteOne = 0x66;
4848static const byte kNopByteTwo = 0x90;
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00004849#ifdef DEBUG
4850static const byte kCallInstruction = 0xe8;
4851#endif
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004852
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004853
4854void BackEdgeTable::PatchAt(Code* unoptimized_code,
4855 Address pc,
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004856 BackEdgeState target_state,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004857 Code* replacement_code) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004858 Address call_target_address = pc - kIntSize;
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004859 Address jns_instr_address = call_target_address - 3;
4860 Address jns_offset_address = call_target_address - 2;
4861
4862 switch (target_state) {
4863 case INTERRUPT:
4864 // sub <profiling_counter>, <delta> ;; Not changed
4865 // jns ok
4866 // call <interrupt stub>
4867 // ok:
4868 *jns_instr_address = kJnsInstruction;
4869 *jns_offset_address = kJnsOffset;
4870 break;
4871 case ON_STACK_REPLACEMENT:
4872 case OSR_AFTER_STACK_CHECK:
4873 // sub <profiling_counter>, <delta> ;; Not changed
4874 // nop
4875 // nop
4876 // call <on-stack replacment>
4877 // ok:
4878 *jns_instr_address = kNopByteOne;
4879 *jns_offset_address = kNopByteTwo;
4880 break;
4881 }
4882
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004883 Assembler::set_target_address_at(call_target_address,
4884 replacement_code->entry());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004885 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
4886 unoptimized_code, call_target_address, replacement_code);
4887}
4888
4889
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004890BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
4891 Isolate* isolate,
4892 Code* unoptimized_code,
4893 Address pc) {
4894 Address call_target_address = pc - kIntSize;
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004895 Address jns_instr_address = call_target_address - 3;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004896 ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004897
4898 if (*jns_instr_address == kJnsInstruction) {
4899 ASSERT_EQ(kJnsOffset, *(call_target_address - 2));
4900 ASSERT_EQ(isolate->builtins()->InterruptCheck()->entry(),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004901 Assembler::target_address_at(call_target_address));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004902 return INTERRUPT;
4903 }
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004904
4905 ASSERT_EQ(kNopByteOne, *jns_instr_address);
4906 ASSERT_EQ(kNopByteTwo, *(call_target_address - 2));
4907
4908 if (Assembler::target_address_at(call_target_address) ==
4909 isolate->builtins()->OnStackReplacement()->entry()) {
4910 return ON_STACK_REPLACEMENT;
4911 }
4912
4913 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(),
4914 Assembler::target_address_at(call_target_address));
4915 return OSR_AFTER_STACK_CHECK;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004916}
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004917
4918
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004919} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004920
4921#endif // V8_TARGET_ARCH_IA32