blob: 62a2c2af3309437ec699a4878614a40d704daafe [file] [log] [blame]
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Block3ce2e202009-11-05 08:53:23 +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
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_IA32)
31
Kristian Monsen80d68ea2010-09-08 11:05:35 +010032#include "code-stubs.h"
Ben Murdoch8b112d22011-06-08 16:22:53 +010033#include "codegen.h"
Steve Blockd0582a62009-12-15 09:54:21 +000034#include "compiler.h"
Leon Clarkee46be812010-01-19 14:06:41 +000035#include "debug.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000036#include "full-codegen.h"
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010037#include "isolate-inl.h"
Steve Block3ce2e202009-11-05 08:53:23 +000038#include "parser.h"
Steve Block6ded16b2010-05-10 14:33:55 +010039#include "scopes.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080040#include "stub-cache.h"
Steve Block3ce2e202009-11-05 08:53:23 +000041
42namespace v8 {
43namespace internal {
44
45#define __ ACCESS_MASM(masm_)
46
Ben Murdochb0fe1622011-05-05 13:52:32 +010047
48class JumpPatchSite BASE_EMBEDDED {
49 public:
Steve Block1e0659c2011-05-24 12:43:12 +010050 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010051#ifdef DEBUG
52 info_emitted_ = false;
53#endif
54 }
55
56 ~JumpPatchSite() {
57 ASSERT(patch_site_.is_bound() == info_emitted_);
58 }
59
Ben Murdoch257744e2011-11-30 15:57:28 +000060 void EmitJumpIfNotSmi(Register reg,
61 Label* target,
62 Label::Distance distance = Label::kFar) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010063 __ test(reg, Immediate(kSmiTagMask));
Ben Murdoch257744e2011-11-30 15:57:28 +000064 EmitJump(not_carry, target, distance); // Always taken before patched.
Ben Murdochb0fe1622011-05-05 13:52:32 +010065 }
66
Ben Murdoch257744e2011-11-30 15:57:28 +000067 void EmitJumpIfSmi(Register reg,
68 Label* target,
69 Label::Distance distance = Label::kFar) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010070 __ test(reg, Immediate(kSmiTagMask));
Ben Murdoch257744e2011-11-30 15:57:28 +000071 EmitJump(carry, target, distance); // Never taken before patched.
Ben Murdochb0fe1622011-05-05 13:52:32 +010072 }
73
74 void EmitPatchInfo() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +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));
Ben Murdochb0fe1622011-05-05 13:52:32 +010079#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000080 info_emitted_ = true;
Ben Murdochb0fe1622011-05-05 13:52:32 +010081#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000082 } else {
83 __ nop(); // Signals no inlined code.
84 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010085 }
86
Ben Murdochb0fe1622011-05-05 13:52:32 +010087 private:
88 // jc will be patched with jz, jnc will become jnz.
Ben Murdoch257744e2011-11-30 15:57:28 +000089 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010090 ASSERT(!patch_site_.is_bound() && !info_emitted_);
91 ASSERT(cc == carry || cc == not_carry);
92 __ bind(&patch_site_);
Ben Murdoch257744e2011-11-30 15:57:28 +000093 __ j(cc, target, distance);
Ben Murdochb0fe1622011-05-05 13:52:32 +010094 }
95
96 MacroAssembler* masm_;
97 Label patch_site_;
98#ifdef DEBUG
99 bool info_emitted_;
100#endif
101};
102
103
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100104// TODO(jkummerow): Obsolete as soon as x64 is updated. Remove.
105int FullCodeGenerator::self_optimization_header_size() {
106 UNREACHABLE();
107 return 13;
108}
109
110
Steve Block3ce2e202009-11-05 08:53:23 +0000111// Generate code for a JS function. On entry to the function the receiver
112// and arguments have been pushed on the stack left to right, with the
113// return address on top of them. The actual argument count matches the
114// formal parameter count expected by the function.
115//
116// The live registers are:
Ben Murdochc7cc0282012-03-05 14:35:55 +0000117// o edi: the JS function object being called (i.e. ourselves)
Steve Block3ce2e202009-11-05 08:53:23 +0000118// o esi: our context
119// o ebp: our caller's frame pointer
120// o esp: stack pointer (pointing to return address)
121//
122// The function builds a JS frame. Please see JavaScriptFrameConstants in
123// frames-ia32.h for its layout.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100124void FullCodeGenerator::Generate() {
125 CompilationInfo* info = info_;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000126 handler_table_ =
127 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100128 profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
129 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget)));
Andrei Popescu31002712010-02-23 13:46:05 +0000130 SetFunctionPosition(function());
Steve Block6ded16b2010-05-10 14:33:55 +0100131 Comment cmnt(masm_, "[ function compiled by full code generator");
Steve Block3ce2e202009-11-05 08:53:23 +0000132
Ben Murdochf87a2032010-10-22 12:50:53 +0100133#ifdef DEBUG
134 if (strlen(FLAG_stop_at) > 0 &&
135 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
136 __ int3();
137 }
138#endif
139
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000140 // Strict mode functions and builtins need to replace the receiver
141 // with undefined when called as functions (without an explicit
142 // receiver object). ecx is zero for method calls and non-zero for
143 // function calls.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000144 if (!info->is_classic_mode() || info->is_native()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000145 Label ok;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000146 __ test(ecx, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000147 __ j(zero, &ok, Label::kNear);
148 // +1 for return address.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000149 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000150 __ mov(ecx, Operand(esp, receiver_offset));
151 __ JumpIfSmi(ecx, &ok);
152 __ CmpObjectType(ecx, JS_GLOBAL_PROXY_TYPE, ecx);
153 __ j(not_equal, &ok, Label::kNear);
Ben Murdoch257744e2011-11-30 15:57:28 +0000154 __ mov(Operand(esp, receiver_offset),
155 Immediate(isolate()->factory()->undefined_value()));
156 __ bind(&ok);
157 }
158
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000159 // Open a frame scope to indicate that there is a frame on the stack. The
160 // MANUAL indicates that the scope shouldn't actually generate code to set up
161 // the frame (that is done below).
162 FrameScope frame_scope(masm_, StackFrame::MANUAL);
163
Iain Merrick75681382010-08-19 15:07:18 +0100164 __ push(ebp); // Caller's frame pointer.
165 __ mov(ebp, esp);
166 __ push(esi); // Callee's context.
167 __ push(edi); // Callee's JS Function.
Steve Block3ce2e202009-11-05 08:53:23 +0000168
Iain Merrick75681382010-08-19 15:07:18 +0100169 { Comment cmnt(masm_, "[ Allocate locals");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000170 int locals_count = info->scope()->num_stack_slots();
Iain Merrick75681382010-08-19 15:07:18 +0100171 if (locals_count == 1) {
Steve Block44f0eee2011-05-26 01:26:41 +0100172 __ push(Immediate(isolate()->factory()->undefined_value()));
Iain Merrick75681382010-08-19 15:07:18 +0100173 } else if (locals_count > 1) {
Steve Block44f0eee2011-05-26 01:26:41 +0100174 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
Iain Merrick75681382010-08-19 15:07:18 +0100175 for (int i = 0; i < locals_count; i++) {
176 __ push(eax);
Steve Blockd0582a62009-12-15 09:54:21 +0000177 }
Steve Block3ce2e202009-11-05 08:53:23 +0000178 }
Iain Merrick75681382010-08-19 15:07:18 +0100179 }
Steve Block3ce2e202009-11-05 08:53:23 +0000180
Iain Merrick75681382010-08-19 15:07:18 +0100181 bool function_in_register = true;
Steve Blockd0582a62009-12-15 09:54:21 +0000182
Iain Merrick75681382010-08-19 15:07:18 +0100183 // Possibly allocate a local context.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000184 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
Iain Merrick75681382010-08-19 15:07:18 +0100185 if (heap_slots > 0) {
186 Comment cmnt(masm_, "[ Allocate local context");
187 // Argument to NewContext is the function, which is still in edi.
188 __ push(edi);
189 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
190 FastNewContextStub stub(heap_slots);
Leon Clarke4515c472010-02-03 11:58:03 +0000191 __ CallStub(&stub);
Iain Merrick75681382010-08-19 15:07:18 +0100192 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000193 __ CallRuntime(Runtime::kNewFunctionContext, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000194 }
Iain Merrick75681382010-08-19 15:07:18 +0100195 function_in_register = false;
196 // Context is returned in both eax and esi. It replaces the context
197 // passed to us. It's saved in the stack and kept live in esi.
198 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
199
200 // Copy parameters into context if necessary.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000201 int num_parameters = info->scope()->num_parameters();
Iain Merrick75681382010-08-19 15:07:18 +0100202 for (int i = 0; i < num_parameters; i++) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000203 Variable* var = scope()->parameter(i);
204 if (var->IsContextSlot()) {
Iain Merrick75681382010-08-19 15:07:18 +0100205 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
206 (num_parameters - 1 - i) * kPointerSize;
207 // Load parameter from stack.
208 __ mov(eax, Operand(ebp, parameter_offset));
209 // Store it in the context.
Ben Murdoch589d6972011-11-30 16:04:58 +0000210 int context_offset = Context::SlotOffset(var->index());
Iain Merrick75681382010-08-19 15:07:18 +0100211 __ mov(Operand(esi, context_offset), eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000212 // Update the write barrier. This clobbers eax and ebx.
213 __ RecordWriteContextSlot(esi,
214 context_offset,
215 eax,
216 ebx,
217 kDontSaveFPRegs);
Iain Merrick75681382010-08-19 15:07:18 +0100218 }
219 }
220 }
221
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100222 Variable* arguments = scope()->arguments();
Iain Merrick75681382010-08-19 15:07:18 +0100223 if (arguments != NULL) {
224 // Function uses arguments object.
225 Comment cmnt(masm_, "[ Allocate arguments object");
226 if (function_in_register) {
227 __ push(edi);
228 } else {
229 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
230 }
231 // Receiver is just before the parameters on the caller's stack.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000232 int num_parameters = info->scope()->num_parameters();
233 int offset = num_parameters * kPointerSize;
Iain Merrick75681382010-08-19 15:07:18 +0100234 __ lea(edx,
235 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
236 __ push(edx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000237 __ SafePush(Immediate(Smi::FromInt(num_parameters)));
Ben Murdochc7cc0282012-03-05 14:35:55 +0000238 // Arguments to ArgumentsAccessStub:
Iain Merrick75681382010-08-19 15:07:18 +0100239 // function, receiver address, parameter count.
240 // The stub will rewrite receiver and parameter count if the previous
241 // stack frame was an arguments adapter frame.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000242 ArgumentsAccessStub::Type type;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000243 if (!is_classic_mode()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000244 type = ArgumentsAccessStub::NEW_STRICT;
245 } else if (function()->has_duplicate_parameters()) {
246 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
247 } else {
248 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
249 }
250 ArgumentsAccessStub stub(type);
Iain Merrick75681382010-08-19 15:07:18 +0100251 __ CallStub(&stub);
Steve Block44f0eee2011-05-26 01:26:41 +0100252
Ben Murdoch589d6972011-11-30 16:04:58 +0000253 SetVar(arguments, eax, ebx, edx);
Steve Blockd0582a62009-12-15 09:54:21 +0000254 }
255
Ben Murdochb0fe1622011-05-05 13:52:32 +0100256 if (FLAG_trace) {
257 __ CallRuntime(Runtime::kTraceEnter, 0);
258 }
259
Steve Block1e0659c2011-05-24 12:43:12 +0100260 // Visit the declarations and body unless there is an illegal
261 // redeclaration.
262 if (scope()->HasIllegalRedeclaration()) {
263 Comment cmnt(masm_, "[ Declarations");
264 scope()->VisitIllegalRedeclaration(this);
265
266 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000267 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
Steve Block1e0659c2011-05-24 12:43:12 +0100268 { Comment cmnt(masm_, "[ Declarations");
269 // For named function expressions, declare the function name as a
270 // constant.
271 if (scope()->is_function_scope() && scope()->function() != NULL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000272 VariableProxy* proxy = scope()->function();
273 ASSERT(proxy->var()->mode() == CONST ||
274 proxy->var()->mode() == CONST_HARMONY);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100275 ASSERT(proxy->var()->location() != Variable::UNALLOCATED);
276 EmitDeclaration(proxy, proxy->var()->mode(), NULL);
Steve Block1e0659c2011-05-24 12:43:12 +0100277 }
278 VisitDeclarations(scope()->declarations());
279 }
280
281 { Comment cmnt(masm_, "[ Stack check");
Ben Murdoch589d6972011-11-30 16:04:58 +0000282 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Ben Murdoch257744e2011-11-30 15:57:28 +0000283 Label ok;
Steve Block1e0659c2011-05-24 12:43:12 +0100284 ExternalReference stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +0100285 ExternalReference::address_of_stack_limit(isolate());
Steve Block1e0659c2011-05-24 12:43:12 +0100286 __ cmp(esp, Operand::StaticVariable(stack_limit));
Ben Murdoch257744e2011-11-30 15:57:28 +0000287 __ j(above_equal, &ok, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +0100288 StackCheckStub stub;
289 __ CallStub(&stub);
290 __ bind(&ok);
291 }
292
293 { Comment cmnt(masm_, "[ Body");
294 ASSERT(loop_depth() == 0);
295 VisitStatements(function()->body());
296 ASSERT(loop_depth() == 0);
297 }
Steve Block3ce2e202009-11-05 08:53:23 +0000298 }
299
Steve Block1e0659c2011-05-24 12:43:12 +0100300 // Always emit a 'return undefined' in case control fell off the end of
301 // the body.
Steve Block3ce2e202009-11-05 08:53:23 +0000302 { Comment cmnt(masm_, "[ return <undefined>;");
Steve Block44f0eee2011-05-26 01:26:41 +0100303 __ mov(eax, isolate()->factory()->undefined_value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100304 EmitReturnSequence();
Steve Blockd0582a62009-12-15 09:54:21 +0000305 }
306}
Steve Block3ce2e202009-11-05 08:53:23 +0000307
Steve Blockd0582a62009-12-15 09:54:21 +0000308
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000309void FullCodeGenerator::ClearAccumulator() {
310 __ Set(eax, Immediate(Smi::FromInt(0)));
311}
312
313
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100314void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
315 __ mov(ebx, Immediate(profiling_counter_));
316 __ sub(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
317 Immediate(Smi::FromInt(delta)));
318}
319
320
321void FullCodeGenerator::EmitProfilingCounterReset() {
322 int reset_value = FLAG_interrupt_budget;
323 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) {
324 // Self-optimization is a one-off thing: if it fails, don't try again.
325 reset_value = Smi::kMaxValue;
326 }
327 if (isolate()->IsDebuggerActive()) {
328 // Detect debug break requests as soon as possible.
329 reset_value = 10;
330 }
331 __ mov(ebx, Immediate(profiling_counter_));
332 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
333 Immediate(Smi::FromInt(reset_value)));
334}
335
336
337static const int kMaxBackEdgeWeight = 127;
338static const int kBackEdgeDistanceDivisor = 100;
339
340
341void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt,
342 Label* back_edge_target) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100343 Comment cmnt(masm_, "[ Stack check");
Ben Murdoch257744e2011-11-30 15:57:28 +0000344 Label ok;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100345
346 if (FLAG_count_based_interrupts) {
347 int weight = 1;
348 if (FLAG_weighted_back_edges) {
349 ASSERT(back_edge_target->is_bound());
350 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
351 weight = Min(kMaxBackEdgeWeight,
352 Max(1, distance / kBackEdgeDistanceDivisor));
353 }
354 EmitProfilingCounterDecrement(weight);
355 __ j(positive, &ok, Label::kNear);
356 InterruptStub stub;
357 __ CallStub(&stub);
358 } else {
359 // Count based interrupts happen often enough when they are enabled
360 // that the additional stack checks are not necessary (they would
361 // only check for interrupts).
362 ExternalReference stack_limit =
363 ExternalReference::address_of_stack_limit(isolate());
364 __ cmp(esp, Operand::StaticVariable(stack_limit));
365 __ j(above_equal, &ok, Label::kNear);
366 StackCheckStub stub;
367 __ CallStub(&stub);
368 }
369
Ben Murdoch086aeea2011-05-13 15:57:08 +0100370 // Record a mapping of this PC offset to the OSR id. This is used to find
371 // the AST id from the unoptimized code in order to use it as a key into
372 // the deoptimization input data found in the optimized code.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100373 RecordStackCheck(stmt->OsrEntryId());
Ben Murdoch086aeea2011-05-13 15:57:08 +0100374
375 // Loop stack checks can be patched to perform on-stack replacement. In
376 // order to decide whether or not to perform OSR we embed the loop depth
377 // in a test instruction after the call so we can extract it from the OSR
378 // builtin.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100379 ASSERT(loop_depth() > 0);
380 __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
Ben Murdoch086aeea2011-05-13 15:57:08 +0100381
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100382 if (FLAG_count_based_interrupts) {
383 EmitProfilingCounterReset();
384 }
385
Ben Murdoch086aeea2011-05-13 15:57:08 +0100386 __ bind(&ok);
387 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
388 // Record a mapping of the OSR id to this PC. This is used if the OSR
389 // entry becomes the target of a bailout. We don't expect it to be, but
390 // we want it to work if it is.
391 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100392}
393
394
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100395void FullCodeGenerator::EmitReturnSequence() {
Steve Blockd0582a62009-12-15 09:54:21 +0000396 Comment cmnt(masm_, "[ Return sequence");
397 if (return_label_.is_bound()) {
398 __ jmp(&return_label_);
399 } else {
400 // Common return label
401 __ bind(&return_label_);
Steve Block3ce2e202009-11-05 08:53:23 +0000402 if (FLAG_trace) {
403 __ push(eax);
404 __ CallRuntime(Runtime::kTraceExit, 1);
405 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100406 if (FLAG_interrupt_at_exit || FLAG_self_optimization) {
407 // Pretend that the exit is a backwards jump to the entry.
408 int weight = 1;
409 if (info_->ShouldSelfOptimize()) {
410 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
411 } else if (FLAG_weighted_back_edges) {
412 int distance = masm_->pc_offset();
413 weight = Min(kMaxBackEdgeWeight,
414 Max(1, distance / kBackEdgeDistanceDivisor));
415 }
416 EmitProfilingCounterDecrement(weight);
417 Label ok;
418 __ j(positive, &ok, Label::kNear);
419 __ push(eax);
420 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) {
421 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
422 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1);
423 } else {
424 InterruptStub stub;
425 __ CallStub(&stub);
426 }
427 __ pop(eax);
428 EmitProfilingCounterReset();
429 __ bind(&ok);
430 }
Steve Blockd0582a62009-12-15 09:54:21 +0000431#ifdef DEBUG
432 // Add a label for checking the size of the code used for returning.
433 Label check_exit_codesize;
434 masm_->bind(&check_exit_codesize);
435#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100436 SetSourcePosition(function()->end_position() - 1);
Steve Block3ce2e202009-11-05 08:53:23 +0000437 __ RecordJSReturn();
438 // Do not use the leave instruction here because it is too short to
439 // patch with the code required by the debugger.
440 __ mov(esp, ebp);
441 __ pop(ebp);
Steve Block1e0659c2011-05-24 12:43:12 +0100442
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000443 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
Steve Block1e0659c2011-05-24 12:43:12 +0100444 __ Ret(arguments_bytes, ecx);
Steve Blockd0582a62009-12-15 09:54:21 +0000445#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block1e0659c2011-05-24 12:43:12 +0100446 // Check that the size of the code used for returning is large enough
447 // for the debugger's requirements.
448 ASSERT(Assembler::kJSReturnSequenceLength <=
449 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
Steve Blockd0582a62009-12-15 09:54:21 +0000450#endif
451 }
452}
453
454
Ben Murdoch589d6972011-11-30 16:04:58 +0000455void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
456 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
Steve Blockd0582a62009-12-15 09:54:21 +0000457}
458
459
Ben Murdoch589d6972011-11-30 16:04:58 +0000460void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
461 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
462 codegen()->GetVar(result_register(), var);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100463}
464
465
Ben Murdoch589d6972011-11-30 16:04:58 +0000466void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
467 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
468 MemOperand operand = codegen()->VarOperand(var, result_register());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100469 // Memory operands can be pushed directly.
Ben Murdoch589d6972011-11-30 16:04:58 +0000470 __ push(operand);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100471}
472
473
Ben Murdoch589d6972011-11-30 16:04:58 +0000474void FullCodeGenerator::TestContext::Plug(Variable* var) const {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100475 // For simplicity we always test the accumulator register.
Ben Murdoch589d6972011-11-30 16:04:58 +0000476 codegen()->GetVar(result_register(), var);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000477 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000478 codegen()->DoTest(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100479}
480
481
482void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
483 UNREACHABLE(); // Not used on IA32.
484}
485
486
487void FullCodeGenerator::AccumulatorValueContext::Plug(
488 Heap::RootListIndex index) const {
489 UNREACHABLE(); // Not used on IA32.
490}
491
492
493void FullCodeGenerator::StackValueContext::Plug(
494 Heap::RootListIndex index) const {
495 UNREACHABLE(); // Not used on IA32.
496}
497
498
499void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
500 UNREACHABLE(); // Not used on IA32.
501}
502
503
504void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
505}
506
507
508void FullCodeGenerator::AccumulatorValueContext::Plug(
509 Handle<Object> lit) const {
Steve Block053d10c2011-06-13 19:13:29 +0100510 if (lit->IsSmi()) {
511 __ SafeSet(result_register(), Immediate(lit));
512 } else {
513 __ Set(result_register(), Immediate(lit));
514 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100515}
516
517
518void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
Steve Block053d10c2011-06-13 19:13:29 +0100519 if (lit->IsSmi()) {
520 __ SafePush(Immediate(lit));
521 } else {
522 __ push(Immediate(lit));
523 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100524}
525
526
527void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000528 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100529 true,
530 true_label_,
531 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100532 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
533 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100534 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100535 } else if (lit->IsTrue() || lit->IsJSObject()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100536 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100537 } else if (lit->IsString()) {
538 if (String::cast(*lit)->length() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100539 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100540 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100541 if (true_label_ != fall_through_) __ jmp(true_label_);
Steve Blockd0582a62009-12-15 09:54:21 +0000542 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100543 } else if (lit->IsSmi()) {
544 if (Smi::cast(*lit)->value() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100545 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100546 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100547 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100548 }
549 } else {
550 // For simplicity we always test the accumulator register.
551 __ mov(result_register(), lit);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000552 codegen()->DoTest(this);
Steve Blockd0582a62009-12-15 09:54:21 +0000553 }
554}
555
556
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100557void FullCodeGenerator::EffectContext::DropAndPlug(int count,
558 Register reg) const {
Leon Clarkee46be812010-01-19 14:06:41 +0000559 ASSERT(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100560 __ Drop(count);
Leon Clarkef7060e22010-06-03 12:02:55 +0100561}
562
563
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100564void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
565 int count,
566 Register reg) const {
567 ASSERT(count > 0);
568 __ Drop(count);
569 __ Move(result_register(), reg);
Leon Clarkee46be812010-01-19 14:06:41 +0000570}
571
572
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100573void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
574 Register reg) const {
575 ASSERT(count > 0);
576 if (count > 1) __ Drop(count - 1);
577 __ mov(Operand(esp, 0), reg);
578}
579
580
581void FullCodeGenerator::TestContext::DropAndPlug(int count,
582 Register reg) const {
583 ASSERT(count > 0);
584 // For simplicity we always test the accumulator register.
585 __ Drop(count);
586 __ Move(result_register(), reg);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000587 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000588 codegen()->DoTest(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100589}
590
591
592void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
593 Label* materialize_false) const {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100594 ASSERT(materialize_true == materialize_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100595 __ bind(materialize_true);
596}
597
598
599void FullCodeGenerator::AccumulatorValueContext::Plug(
600 Label* materialize_true,
601 Label* materialize_false) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000602 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100603 __ bind(materialize_true);
Steve Block44f0eee2011-05-26 01:26:41 +0100604 __ mov(result_register(), isolate()->factory()->true_value());
Ben Murdoch257744e2011-11-30 15:57:28 +0000605 __ jmp(&done, Label::kNear);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100606 __ bind(materialize_false);
Steve Block44f0eee2011-05-26 01:26:41 +0100607 __ mov(result_register(), isolate()->factory()->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100608 __ bind(&done);
609}
610
611
612void FullCodeGenerator::StackValueContext::Plug(
613 Label* materialize_true,
614 Label* materialize_false) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000615 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100616 __ bind(materialize_true);
Steve Block44f0eee2011-05-26 01:26:41 +0100617 __ push(Immediate(isolate()->factory()->true_value()));
Ben Murdoch257744e2011-11-30 15:57:28 +0000618 __ jmp(&done, Label::kNear);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100619 __ bind(materialize_false);
Steve Block44f0eee2011-05-26 01:26:41 +0100620 __ push(Immediate(isolate()->factory()->false_value()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100621 __ bind(&done);
622}
623
624
625void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
626 Label* materialize_false) const {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100627 ASSERT(materialize_true == true_label_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100628 ASSERT(materialize_false == false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100629}
630
631
632void FullCodeGenerator::EffectContext::Plug(bool flag) const {
633}
634
635
636void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100637 Handle<Object> value = flag
638 ? isolate()->factory()->true_value()
639 : isolate()->factory()->false_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100640 __ mov(result_register(), value);
641}
642
643
644void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100645 Handle<Object> value = flag
646 ? isolate()->factory()->true_value()
647 : isolate()->factory()->false_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100648 __ push(Immediate(value));
649}
650
651
652void FullCodeGenerator::TestContext::Plug(bool flag) const {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000653 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100654 true,
655 true_label_,
656 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100657 if (flag) {
658 if (true_label_ != fall_through_) __ jmp(true_label_);
659 } else {
660 if (false_label_ != fall_through_) __ jmp(false_label_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100661 }
662}
663
664
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000665void FullCodeGenerator::DoTest(Expression* condition,
666 Label* if_true,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100667 Label* if_false,
668 Label* fall_through) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000669 ToBooleanStub stub(result_register());
Leon Clarkee46be812010-01-19 14:06:41 +0000670 __ push(result_register());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000671 __ CallStub(&stub, condition->test_id());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000672 __ test(result_register(), result_register());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100673 // The stub returns nonzero for true.
674 Split(not_zero, if_true, if_false, fall_through);
675}
Leon Clarkee46be812010-01-19 14:06:41 +0000676
Leon Clarkee46be812010-01-19 14:06:41 +0000677
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100678void FullCodeGenerator::Split(Condition cc,
679 Label* if_true,
680 Label* if_false,
681 Label* fall_through) {
682 if (if_false == fall_through) {
683 __ j(cc, if_true);
684 } else if (if_true == fall_through) {
685 __ j(NegateCondition(cc), if_false);
686 } else {
687 __ j(cc, if_true);
688 __ jmp(if_false);
Leon Clarkee46be812010-01-19 14:06:41 +0000689 }
690}
691
692
Ben Murdoch589d6972011-11-30 16:04:58 +0000693MemOperand FullCodeGenerator::StackOperand(Variable* var) {
694 ASSERT(var->IsStackAllocated());
695 // Offset is negative because higher indexes are at lower addresses.
696 int offset = -var->index() * kPointerSize;
697 // Adjust by a (parameter or local) base offset.
698 if (var->IsParameter()) {
699 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
700 } else {
701 offset += JavaScriptFrameConstants::kLocal0Offset;
Leon Clarkee46be812010-01-19 14:06:41 +0000702 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000703 return Operand(ebp, offset);
Leon Clarkee46be812010-01-19 14:06:41 +0000704}
705
706
Ben Murdoch589d6972011-11-30 16:04:58 +0000707MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
708 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
709 if (var->IsContextSlot()) {
710 int context_chain_length = scope()->ContextChainLength(var->scope());
711 __ LoadContext(scratch, context_chain_length);
712 return ContextOperand(scratch, var->index());
713 } else {
714 return StackOperand(var);
715 }
Leon Clarkee46be812010-01-19 14:06:41 +0000716}
717
718
Ben Murdoch589d6972011-11-30 16:04:58 +0000719void FullCodeGenerator::GetVar(Register dest, Variable* var) {
720 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
721 MemOperand location = VarOperand(var, dest);
722 __ mov(dest, location);
723}
724
725
726void FullCodeGenerator::SetVar(Variable* var,
727 Register src,
728 Register scratch0,
729 Register scratch1) {
730 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
731 ASSERT(!scratch0.is(src));
732 ASSERT(!scratch0.is(scratch1));
733 ASSERT(!scratch1.is(src));
734 MemOperand location = VarOperand(var, scratch0);
Leon Clarkee46be812010-01-19 14:06:41 +0000735 __ mov(location, src);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000736
Leon Clarkee46be812010-01-19 14:06:41 +0000737 // Emit the write barrier code if the location is in the heap.
Ben Murdoch589d6972011-11-30 16:04:58 +0000738 if (var->IsContextSlot()) {
739 int offset = Context::SlotOffset(var->index());
740 ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000741 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
Steve Blockd0582a62009-12-15 09:54:21 +0000742 }
743}
744
745
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000746void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100747 bool should_normalize,
748 Label* if_true,
749 Label* if_false) {
750 // Only prepare for bailouts before splits if we're in a test
751 // context. Otherwise, we let the Visit function deal with the
752 // preparation to avoid preparing with the same AST id twice.
753 if (!context()->IsTest() || !info_->IsOptimizable()) return;
754
Ben Murdoch257744e2011-11-30 15:57:28 +0000755 Label skip;
756 if (should_normalize) __ jmp(&skip, Label::kNear);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000757 PrepareForBailout(expr, TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100758 if (should_normalize) {
Steve Block44f0eee2011-05-26 01:26:41 +0100759 __ cmp(eax, isolate()->factory()->true_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100760 Split(equal, if_true, if_false, NULL);
761 __ bind(&skip);
762 }
763}
764
765
Ben Murdoch589d6972011-11-30 16:04:58 +0000766void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000767 VariableMode mode,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100768 FunctionLiteral* function) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000769 // If it was not possible to allocate the variable at compile time, we
770 // need to "declare" it at runtime to make sure it actually exists in the
771 // local context.
772 Variable* variable = proxy->var();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000773 bool binding_needs_init = (function == NULL) &&
774 (mode == CONST || mode == CONST_HARMONY || mode == LET);
Ben Murdoch589d6972011-11-30 16:04:58 +0000775 switch (variable->location()) {
776 case Variable::UNALLOCATED:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100777 ++global_count_;
Ben Murdoch589d6972011-11-30 16:04:58 +0000778 break;
779
780 case Variable::PARAMETER:
781 case Variable::LOCAL:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000782 if (function != NULL) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000783 Comment cmnt(masm_, "[ Declaration");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000784 VisitForAccumulatorValue(function);
Ben Murdoch589d6972011-11-30 16:04:58 +0000785 __ mov(StackOperand(variable), result_register());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000786 } else if (binding_needs_init) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000787 Comment cmnt(masm_, "[ Declaration");
788 __ mov(StackOperand(variable),
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000789 Immediate(isolate()->factory()->the_hole_value()));
Steve Blockd0582a62009-12-15 09:54:21 +0000790 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000791 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000792
Ben Murdoch589d6972011-11-30 16:04:58 +0000793 case Variable::CONTEXT:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000794 // The variable in the decl always resides in the current function
795 // context.
796 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
797 if (FLAG_debug_code) {
798 // Check that we're not inside a with or catch context.
799 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
800 __ cmp(ebx, isolate()->factory()->with_context_map());
801 __ Check(not_equal, "Declaration in with context.");
802 __ cmp(ebx, isolate()->factory()->catch_context_map());
803 __ Check(not_equal, "Declaration in catch context.");
Steve Blockd0582a62009-12-15 09:54:21 +0000804 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000805 if (function != NULL) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000806 Comment cmnt(masm_, "[ Declaration");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000807 VisitForAccumulatorValue(function);
Ben Murdoch589d6972011-11-30 16:04:58 +0000808 __ mov(ContextOperand(esi, variable->index()), result_register());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000809 // We know that we have written a function, which is not a smi.
810 __ RecordWriteContextSlot(esi,
811 Context::SlotOffset(variable->index()),
812 result_register(),
813 ecx,
814 kDontSaveFPRegs,
815 EMIT_REMEMBERED_SET,
816 OMIT_SMI_CHECK);
Ben Murdoch589d6972011-11-30 16:04:58 +0000817 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000818 } else if (binding_needs_init) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000819 Comment cmnt(masm_, "[ Declaration");
820 __ mov(ContextOperand(esi, variable->index()),
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000821 Immediate(isolate()->factory()->the_hole_value()));
822 // No write barrier since the hole value is in old space.
Ben Murdoch589d6972011-11-30 16:04:58 +0000823 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000824 }
825 break;
Steve Block1e0659c2011-05-24 12:43:12 +0100826
Ben Murdoch589d6972011-11-30 16:04:58 +0000827 case Variable::LOOKUP: {
828 Comment cmnt(masm_, "[ Declaration");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000829 __ push(esi);
830 __ push(Immediate(variable->name()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000831 // Declaration nodes are always introduced in one of four modes.
832 ASSERT(mode == VAR ||
833 mode == CONST ||
834 mode == CONST_HARMONY ||
835 mode == LET);
836 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY)
837 ? READ_ONLY : NONE;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000838 __ push(Immediate(Smi::FromInt(attr)));
839 // Push initial value, if any.
840 // Note: For variables we must not push an initial value (such as
841 // 'undefined') because we may have a (legal) redeclaration and we
842 // must not destroy the current value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000843 if (function != NULL) {
844 VisitForStackValue(function);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000845 } else if (binding_needs_init) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000846 __ push(Immediate(isolate()->factory()->the_hole_value()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000847 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000848 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000849 }
850 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000851 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000852 }
Steve Block3ce2e202009-11-05 08:53:23 +0000853 }
854}
855
856
Leon Clarked91b9f72010-01-27 17:25:45 +0000857void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
Steve Block3ce2e202009-11-05 08:53:23 +0000858 // Call the runtime to declare the globals.
859 __ push(esi); // The context is the first argument.
860 __ push(Immediate(pairs));
Ben Murdoch589d6972011-11-30 16:04:58 +0000861 __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags())));
862 __ CallRuntime(Runtime::kDeclareGlobals, 3);
Steve Block3ce2e202009-11-05 08:53:23 +0000863 // Return value is ignored.
864}
865
866
Leon Clarkef7060e22010-06-03 12:02:55 +0100867void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
868 Comment cmnt(masm_, "[ SwitchStatement");
869 Breakable nested_statement(this, stmt);
870 SetStatementPosition(stmt);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100871
Leon Clarkef7060e22010-06-03 12:02:55 +0100872 // Keep the switch value on the stack until a case matches.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100873 VisitForStackValue(stmt->tag());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100874 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +0000875
Leon Clarkef7060e22010-06-03 12:02:55 +0100876 ZoneList<CaseClause*>* clauses = stmt->cases();
877 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
Steve Block3ce2e202009-11-05 08:53:23 +0000878
Leon Clarkef7060e22010-06-03 12:02:55 +0100879 Label next_test; // Recycled for each test.
880 // Compile all the tests with branches to their bodies.
881 for (int i = 0; i < clauses->length(); i++) {
882 CaseClause* clause = clauses->at(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100883 clause->body_target()->Unuse();
Steve Block1e0659c2011-05-24 12:43:12 +0100884
Leon Clarkef7060e22010-06-03 12:02:55 +0100885 // The default is not a test, but remember it as final fall through.
886 if (clause->is_default()) {
887 default_clause = clause;
888 continue;
889 }
890
891 Comment cmnt(masm_, "[ Case comparison");
892 __ bind(&next_test);
893 next_test.Unuse();
894
895 // Compile the label expression.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100896 VisitForAccumulatorValue(clause->label());
Leon Clarkef7060e22010-06-03 12:02:55 +0100897
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100898 // Perform the comparison as if via '==='.
Leon Clarkef7060e22010-06-03 12:02:55 +0100899 __ mov(edx, Operand(esp, 0)); // Switch value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100900 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100901 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100902 if (inline_smi_code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000903 Label slow_case;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100904 __ mov(ecx, edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000905 __ or_(ecx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +0000906 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100907
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000908 __ cmp(edx, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100909 __ j(not_equal, &next_test);
910 __ Drop(1); // Switch value is no longer needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100911 __ jmp(clause->body_target());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100912 __ bind(&slow_case);
913 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100914
Ben Murdochb0fe1622011-05-05 13:52:32 +0100915 // Record position before stub call for type feedback.
916 SetSourcePosition(clause->position());
917 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100918 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000919 patch_site.EmitPatchInfo();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000920 __ test(eax, eax);
Leon Clarkef7060e22010-06-03 12:02:55 +0100921 __ j(not_equal, &next_test);
922 __ Drop(1); // Switch value is no longer needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100923 __ jmp(clause->body_target());
Leon Clarkef7060e22010-06-03 12:02:55 +0100924 }
925
926 // Discard the test value and jump to the default if present, otherwise to
927 // the end of the statement.
928 __ bind(&next_test);
929 __ Drop(1); // Switch value is no longer needed.
930 if (default_clause == NULL) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000931 __ jmp(nested_statement.break_label());
Leon Clarkef7060e22010-06-03 12:02:55 +0100932 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100933 __ jmp(default_clause->body_target());
Leon Clarkef7060e22010-06-03 12:02:55 +0100934 }
935
936 // Compile all the case bodies.
937 for (int i = 0; i < clauses->length(); i++) {
938 Comment cmnt(masm_, "[ Case body");
939 CaseClause* clause = clauses->at(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100940 __ bind(clause->body_target());
Steve Block44f0eee2011-05-26 01:26:41 +0100941 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +0100942 VisitStatements(clause->statements());
943 }
944
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000945 __ bind(nested_statement.break_label());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100946 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +0100947}
948
949
950void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
951 Comment cmnt(masm_, "[ ForInStatement");
952 SetStatementPosition(stmt);
953
954 Label loop, exit;
955 ForIn loop_statement(this, stmt);
956 increment_loop_depth();
957
958 // Get the object to enumerate over. Both SpiderMonkey and JSC
959 // ignore null and undefined in contrast to the specification; see
960 // ECMA-262 section 12.6.4.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100961 VisitForAccumulatorValue(stmt->enumerable());
Steve Block44f0eee2011-05-26 01:26:41 +0100962 __ cmp(eax, isolate()->factory()->undefined_value());
Leon Clarkef7060e22010-06-03 12:02:55 +0100963 __ j(equal, &exit);
Steve Block44f0eee2011-05-26 01:26:41 +0100964 __ cmp(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +0100965 __ j(equal, &exit);
966
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100967 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
968
Leon Clarkef7060e22010-06-03 12:02:55 +0100969 // Convert the object to a JS object.
Ben Murdoch257744e2011-11-30 15:57:28 +0000970 Label convert, done_convert;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000971 __ JumpIfSmi(eax, &convert, Label::kNear);
972 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000973 __ j(above_equal, &done_convert, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +0100974 __ bind(&convert);
975 __ push(eax);
976 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
977 __ bind(&done_convert);
978 __ push(eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000979
980 // Check for proxies.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100981 Label call_runtime, use_cache, fixed_array;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000982 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
983 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
984 __ j(below_equal, &call_runtime);
Leon Clarkef7060e22010-06-03 12:02:55 +0100985
Steve Block59151502010-09-22 15:07:15 +0100986 // Check cache validity in generated code. This is a fast case for
987 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
988 // guarantee cache validity, call the runtime system to check cache
989 // validity or get the property names in a fixed array.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100990 __ CheckEnumCache(&call_runtime);
Steve Block59151502010-09-22 15:07:15 +0100991
Steve Block59151502010-09-22 15:07:15 +0100992 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +0000993 __ jmp(&use_cache, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +0100994
995 // Get the set of properties to enumerate.
Steve Block59151502010-09-22 15:07:15 +0100996 __ bind(&call_runtime);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100997 __ push(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +0100998 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
Steve Block44f0eee2011-05-26 01:26:41 +0100999 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1000 isolate()->factory()->meta_map());
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001001 __ j(not_equal, &fixed_array);
1002
Leon Clarkef7060e22010-06-03 12:02:55 +01001003
1004 // We got a map in register eax. Get the enumeration cache from it.
Steve Block59151502010-09-22 15:07:15 +01001005 __ bind(&use_cache);
Ben Murdoch257744e2011-11-30 15:57:28 +00001006 __ LoadInstanceDescriptors(eax, ecx);
Leon Clarkef7060e22010-06-03 12:02:55 +01001007 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
1008 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1009
Ben Murdochc7cc0282012-03-05 14:35:55 +00001010 // Set up the four remaining stack slots.
Leon Clarkef7060e22010-06-03 12:02:55 +01001011 __ push(eax); // Map.
1012 __ push(edx); // Enumeration cache.
1013 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01001014 __ push(eax); // Enumeration cache length (as smi).
1015 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1016 __ jmp(&loop);
1017
1018 // We got a fixed array in register eax. Iterate through that.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001019 Label non_proxy;
Leon Clarkef7060e22010-06-03 12:02:55 +01001020 __ bind(&fixed_array);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001021
1022 Handle<JSGlobalPropertyCell> cell =
1023 isolate()->factory()->NewJSGlobalPropertyCell(
1024 Handle<Object>(
1025 Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
1026 RecordTypeFeedbackCell(stmt->PrepareId(), cell);
1027 __ LoadHeapObject(ebx, cell);
1028 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
1029 Immediate(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker)));
1030
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001031 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
1032 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
1033 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1034 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
1035 __ j(above, &non_proxy);
1036 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
1037 __ bind(&non_proxy);
1038 __ push(ebx); // Smi
1039 __ push(eax); // Array
Leon Clarkef7060e22010-06-03 12:02:55 +01001040 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01001041 __ push(eax); // Fixed array length (as smi).
1042 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1043
1044 // Generate code for doing the condition check.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001045 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001046 __ bind(&loop);
1047 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1048 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001049 __ j(above_equal, loop_statement.break_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001050
1051 // Get the current entry of the array into register ebx.
1052 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1053 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1054
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001055 // Get the expected map from the stack or a smi in the
Leon Clarkef7060e22010-06-03 12:02:55 +01001056 // permanent slow case into register edx.
1057 __ mov(edx, Operand(esp, 3 * kPointerSize));
1058
1059 // Check if the expected map still matches that of the enumerable.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001060 // If not, we may have to filter the key.
Ben Murdoch257744e2011-11-30 15:57:28 +00001061 Label update_each;
Leon Clarkef7060e22010-06-03 12:02:55 +01001062 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1063 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001064 __ j(equal, &update_each, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01001065
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001066 // For proxies, no filtering is done.
1067 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1068 ASSERT(Smi::FromInt(0) == 0);
1069 __ test(edx, edx);
1070 __ j(zero, &update_each);
1071
Leon Clarkef7060e22010-06-03 12:02:55 +01001072 // Convert the entry to a string or null if it isn't a property
1073 // anymore. If the property has been removed while iterating, we
1074 // just skip it.
1075 __ push(ecx); // Enumerable.
1076 __ push(ebx); // Current entry.
1077 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001078 __ test(eax, eax);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001079 __ j(equal, loop_statement.continue_label());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001080 __ mov(ebx, eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001081
1082 // Update the 'each' property or variable from the possibly filtered
1083 // entry in register ebx.
1084 __ bind(&update_each);
1085 __ mov(result_register(), ebx);
1086 // Perform the assignment as if via '='.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001087 { EffectContext context(this);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001088 EmitAssignment(stmt->each());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001089 }
Leon Clarkef7060e22010-06-03 12:02:55 +01001090
1091 // Generate code for the body of the loop.
Leon Clarkef7060e22010-06-03 12:02:55 +01001092 Visit(stmt->body());
1093
Leon Clarkef7060e22010-06-03 12:02:55 +01001094 // Generate code for going to the next element by incrementing the
1095 // index (smi) stored on top of the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001096 __ bind(loop_statement.continue_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001097 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
Leon Clarkef7060e22010-06-03 12:02:55 +01001098
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001099 EmitStackCheck(stmt, &loop);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001100 __ jmp(&loop);
Leon Clarkef7060e22010-06-03 12:02:55 +01001101
1102 // Remove the pointers stored on the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001103 __ bind(loop_statement.break_label());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001104 __ add(esp, Immediate(5 * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01001105
1106 // Exit and decrement the loop depth.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001107 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001108 __ bind(&exit);
1109 decrement_loop_depth();
1110}
1111
1112
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001113void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1114 bool pretenure) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001115 // Use the fast case closure allocation code that allocates in new
Ben Murdochb0fe1622011-05-05 13:52:32 +01001116 // space for nested functions that don't need literals cloning. If
1117 // we're running with the --always-opt or the --prepare-always-opt
1118 // flag, we need to use the runtime function so that the new function
1119 // we are creating here gets a chance to have its code optimized and
1120 // doesn't just get a copy of the existing unoptimized code.
1121 if (!FLAG_always_opt &&
1122 !FLAG_prepare_always_opt &&
Steve Block44f0eee2011-05-26 01:26:41 +01001123 !pretenure &&
Ben Murdochb0fe1622011-05-05 13:52:32 +01001124 scope()->is_function_scope() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001125 info->num_literals() == 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001126 FastNewClosureStub stub(info->language_mode());
Leon Clarkef7060e22010-06-03 12:02:55 +01001127 __ push(Immediate(info));
1128 __ CallStub(&stub);
1129 } else {
1130 __ push(esi);
1131 __ push(Immediate(info));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001132 __ push(Immediate(pretenure
Steve Block44f0eee2011-05-26 01:26:41 +01001133 ? isolate()->factory()->true_value()
1134 : isolate()->factory()->false_value()));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001135 __ CallRuntime(Runtime::kNewClosure, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001136 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001137 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001138}
1139
1140
Leon Clarked91b9f72010-01-27 17:25:45 +00001141void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001142 Comment cmnt(masm_, "[ VariableProxy");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001143 EmitVariableLoad(expr);
Leon Clarkee46be812010-01-19 14:06:41 +00001144}
1145
1146
Ben Murdoch589d6972011-11-30 16:04:58 +00001147void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1148 TypeofState typeof_state,
1149 Label* slow) {
Steve Block59151502010-09-22 15:07:15 +01001150 Register context = esi;
1151 Register temp = edx;
1152
1153 Scope* s = scope();
1154 while (s != NULL) {
1155 if (s->num_heap_slots() > 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001156 if (s->calls_non_strict_eval()) {
Steve Block59151502010-09-22 15:07:15 +01001157 // Check that extension is NULL.
1158 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1159 Immediate(0));
1160 __ j(not_equal, slow);
1161 }
1162 // Load next context in chain.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001163 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001164 // Walk the rest of the chain without clobbering esi.
1165 context = temp;
1166 }
1167 // If no outer scope calls eval, we do not need to check more
1168 // context extensions. If we have reached an eval scope, we check
1169 // all extensions from this point.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001170 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
Steve Block59151502010-09-22 15:07:15 +01001171 s = s->outer_scope();
1172 }
1173
1174 if (s != NULL && s->is_eval_scope()) {
1175 // Loop up the context chain. There is no frame effect so it is
1176 // safe to use raw labels here.
Ben Murdoch257744e2011-11-30 15:57:28 +00001177 Label next, fast;
Steve Block59151502010-09-22 15:07:15 +01001178 if (!context.is(temp)) {
1179 __ mov(temp, context);
1180 }
1181 __ bind(&next);
1182 // Terminate at global context.
1183 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01001184 Immediate(isolate()->factory()->global_context_map()));
Ben Murdoch257744e2011-11-30 15:57:28 +00001185 __ j(equal, &fast, Label::kNear);
Steve Block59151502010-09-22 15:07:15 +01001186 // Check that extension is NULL.
1187 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1188 __ j(not_equal, slow);
1189 // Load next context in chain.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001190 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001191 __ jmp(&next);
1192 __ bind(&fast);
1193 }
1194
1195 // All extension objects were empty and it is safe to use a global
1196 // load IC call.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001197 __ mov(eax, GlobalObjectOperand());
Ben Murdoch589d6972011-11-30 16:04:58 +00001198 __ mov(ecx, var->name());
Steve Block44f0eee2011-05-26 01:26:41 +01001199 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
Steve Block59151502010-09-22 15:07:15 +01001200 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1201 ? RelocInfo::CODE_TARGET
1202 : RelocInfo::CODE_TARGET_CONTEXT;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001203 CallIC(ic, mode);
Steve Block59151502010-09-22 15:07:15 +01001204}
1205
1206
Ben Murdoch589d6972011-11-30 16:04:58 +00001207MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1208 Label* slow) {
1209 ASSERT(var->IsContextSlot());
Steve Block59151502010-09-22 15:07:15 +01001210 Register context = esi;
1211 Register temp = ebx;
1212
Ben Murdoch589d6972011-11-30 16:04:58 +00001213 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
Steve Block59151502010-09-22 15:07:15 +01001214 if (s->num_heap_slots() > 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001215 if (s->calls_non_strict_eval()) {
Steve Block59151502010-09-22 15:07:15 +01001216 // Check that extension is NULL.
1217 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1218 Immediate(0));
1219 __ j(not_equal, slow);
1220 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001221 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001222 // Walk the rest of the chain without clobbering esi.
1223 context = temp;
1224 }
1225 }
1226 // Check that last extension is NULL.
1227 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1228 __ j(not_equal, slow);
Steve Block1e0659c2011-05-24 12:43:12 +01001229
1230 // This function is used only for loads, not stores, so it's safe to
1231 // return an esi-based operand (the write barrier cannot be allowed to
1232 // destroy the esi register).
Ben Murdoch589d6972011-11-30 16:04:58 +00001233 return ContextOperand(context, var->index());
Steve Block59151502010-09-22 15:07:15 +01001234}
1235
1236
Ben Murdoch589d6972011-11-30 16:04:58 +00001237void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1238 TypeofState typeof_state,
1239 Label* slow,
1240 Label* done) {
Steve Block59151502010-09-22 15:07:15 +01001241 // Generate fast-case code for variables that might be shadowed by
1242 // eval-introduced variables. Eval is used a lot without
1243 // introducing variables. In those cases, we do not want to
1244 // perform a runtime call for all variables in the scope
1245 // containing the eval.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001246 if (var->mode() == DYNAMIC_GLOBAL) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001247 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
Steve Block59151502010-09-22 15:07:15 +01001248 __ jmp(done);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001249 } else if (var->mode() == DYNAMIC_LOCAL) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001250 Variable* local = var->local_if_not_shadowed();
1251 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001252 if (local->mode() == CONST ||
1253 local->mode() == CONST_HARMONY ||
1254 local->mode() == LET) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001255 __ cmp(eax, isolate()->factory()->the_hole_value());
1256 __ j(not_equal, done);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001257 if (local->mode() == CONST) {
1258 __ mov(eax, isolate()->factory()->undefined_value());
1259 } else { // LET || CONST_HARMONY
1260 __ push(Immediate(var->name()));
1261 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1262 }
Steve Block59151502010-09-22 15:07:15 +01001263 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001264 __ jmp(done);
Steve Block59151502010-09-22 15:07:15 +01001265 }
1266}
1267
1268
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001269void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1270 // Record position before possible IC call.
1271 SetSourcePosition(proxy->position());
1272 Variable* var = proxy->var();
Leon Clarked91b9f72010-01-27 17:25:45 +00001273
Ben Murdoch589d6972011-11-30 16:04:58 +00001274 // Three cases: global variables, lookup variables, and all other types of
1275 // variables.
1276 switch (var->location()) {
1277 case Variable::UNALLOCATED: {
1278 Comment cmnt(masm_, "Global variable");
1279 // Use inline caching. Variable name is passed in ecx and the global
1280 // object in eax.
1281 __ mov(eax, GlobalObjectOperand());
1282 __ mov(ecx, var->name());
1283 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001284 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001285 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00001286 break;
1287 }
1288
1289 case Variable::PARAMETER:
1290 case Variable::LOCAL:
1291 case Variable::CONTEXT: {
1292 Comment cmnt(masm_, var->IsContextSlot()
1293 ? "Context variable"
1294 : "Stack variable");
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001295 if (var->binding_needs_init()) {
1296 // var->scope() may be NULL when the proxy is located in eval code and
1297 // refers to a potential outside binding. Currently those bindings are
1298 // always looked up dynamically, i.e. in that case
1299 // var->location() == LOOKUP.
1300 // always holds.
1301 ASSERT(var->scope() != NULL);
1302
1303 // Check if the binding really needs an initialization check. The check
1304 // can be skipped in the following situation: we have a LET or CONST
1305 // binding in harmony mode, both the Variable and the VariableProxy have
1306 // the same declaration scope (i.e. they are both in global code, in the
1307 // same function or in the same eval code) and the VariableProxy is in
1308 // the source physically located after the initializer of the variable.
1309 //
1310 // We cannot skip any initialization checks for CONST in non-harmony
1311 // mode because const variables may be declared but never initialized:
1312 // if (false) { const x; }; var y = x;
1313 //
1314 // The condition on the declaration scopes is a conservative check for
1315 // nested functions that access a binding and are called before the
1316 // binding is initialized:
1317 // function() { f(); let x = 1; function f() { x = 2; } }
1318 //
1319 bool skip_init_check;
1320 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1321 skip_init_check = false;
1322 } else {
1323 // Check that we always have valid source position.
1324 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1325 ASSERT(proxy->position() != RelocInfo::kNoPosition);
1326 skip_init_check = var->mode() != CONST &&
1327 var->initializer_position() < proxy->position();
Ben Murdoch589d6972011-11-30 16:04:58 +00001328 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001329
1330 if (!skip_init_check) {
1331 // Let and const need a read barrier.
1332 Label done;
1333 GetVar(eax, var);
1334 __ cmp(eax, isolate()->factory()->the_hole_value());
1335 __ j(not_equal, &done, Label::kNear);
1336 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1337 // Throw a reference error when using an uninitialized let/const
1338 // binding in harmony mode.
1339 __ push(Immediate(var->name()));
1340 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1341 } else {
1342 // Uninitalized const bindings outside of harmony mode are unholed.
1343 ASSERT(var->mode() == CONST);
1344 __ mov(eax, isolate()->factory()->undefined_value());
1345 }
1346 __ bind(&done);
1347 context()->Plug(eax);
1348 break;
1349 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001350 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001351 context()->Plug(var);
Ben Murdoch589d6972011-11-30 16:04:58 +00001352 break;
1353 }
1354
1355 case Variable::LOOKUP: {
1356 Label done, slow;
1357 // Generate code for loading from variables potentially shadowed
1358 // by eval-introduced variables.
1359 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1360 __ bind(&slow);
1361 Comment cmnt(masm_, "Lookup variable");
1362 __ push(esi); // Context.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001363 __ push(Immediate(var->name()));
Ben Murdoch589d6972011-11-30 16:04:58 +00001364 __ CallRuntime(Runtime::kLoadContextSlot, 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001365 __ bind(&done);
1366 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00001367 break;
Leon Clarkef7060e22010-06-03 12:02:55 +01001368 }
Steve Block3ce2e202009-11-05 08:53:23 +00001369 }
1370}
1371
1372
Leon Clarked91b9f72010-01-27 17:25:45 +00001373void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001374 Comment cmnt(masm_, "[ RegExpLiteral");
Ben Murdoch257744e2011-11-30 15:57:28 +00001375 Label materialized;
Steve Block3ce2e202009-11-05 08:53:23 +00001376 // Registers will be used as follows:
1377 // edi = JS function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001378 // ecx = literals array.
1379 // ebx = regexp literal.
1380 // eax = regexp literal clone.
Steve Block3ce2e202009-11-05 08:53:23 +00001381 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdochbb769b22010-08-11 14:56:33 +01001382 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001383 int literal_offset =
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001384 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
Ben Murdochbb769b22010-08-11 14:56:33 +01001385 __ mov(ebx, FieldOperand(ecx, literal_offset));
Steve Block44f0eee2011-05-26 01:26:41 +01001386 __ cmp(ebx, isolate()->factory()->undefined_value());
Ben Murdoch257744e2011-11-30 15:57:28 +00001387 __ j(not_equal, &materialized, Label::kNear);
Ben Murdochbb769b22010-08-11 14:56:33 +01001388
Steve Block3ce2e202009-11-05 08:53:23 +00001389 // Create regexp literal using runtime function
1390 // Result will be in eax.
Ben Murdochbb769b22010-08-11 14:56:33 +01001391 __ push(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001392 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1393 __ push(Immediate(expr->pattern()));
1394 __ push(Immediate(expr->flags()));
1395 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
Ben Murdochbb769b22010-08-11 14:56:33 +01001396 __ mov(ebx, eax);
1397
1398 __ bind(&materialized);
1399 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1400 Label allocated, runtime_allocate;
1401 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1402 __ jmp(&allocated);
1403
1404 __ bind(&runtime_allocate);
1405 __ push(ebx);
1406 __ push(Immediate(Smi::FromInt(size)));
1407 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1408 __ pop(ebx);
1409
1410 __ bind(&allocated);
1411 // Copy the content into the newly allocated memory.
1412 // (Unroll copy loop once for better throughput).
1413 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1414 __ mov(edx, FieldOperand(ebx, i));
1415 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1416 __ mov(FieldOperand(eax, i), edx);
1417 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1418 }
1419 if ((size % (2 * kPointerSize)) != 0) {
1420 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1421 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1422 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001423 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00001424}
1425
1426
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001427void FullCodeGenerator::EmitAccessor(Expression* expression) {
1428 if (expression == NULL) {
1429 __ push(Immediate(isolate()->factory()->null_value()));
1430 } else {
1431 VisitForStackValue(expression);
1432 }
1433}
1434
1435
Leon Clarked91b9f72010-01-27 17:25:45 +00001436void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001437 Comment cmnt(masm_, "[ ObjectLiteral");
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001438 Handle<FixedArray> constant_properties = expr->constant_properties();
Steve Blockd0582a62009-12-15 09:54:21 +00001439 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00001440 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Blockd0582a62009-12-15 09:54:21 +00001441 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001442 __ push(Immediate(constant_properties));
Steve Block44f0eee2011-05-26 01:26:41 +01001443 int flags = expr->fast_elements()
1444 ? ObjectLiteral::kFastElements
1445 : ObjectLiteral::kNoFlags;
1446 flags |= expr->has_function()
1447 ? ObjectLiteral::kHasFunction
1448 : ObjectLiteral::kNoFlags;
1449 __ push(Immediate(Smi::FromInt(flags)));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001450 int properties_count = constant_properties->length() / 2;
Leon Clarkee46be812010-01-19 14:06:41 +00001451 if (expr->depth() > 1) {
Steve Block6ded16b2010-05-10 14:33:55 +01001452 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001453 } else if (flags != ObjectLiteral::kFastElements ||
1454 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
Steve Block6ded16b2010-05-10 14:33:55 +01001455 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001456 } else {
1457 FastCloneShallowObjectStub stub(properties_count);
1458 __ CallStub(&stub);
Steve Blockd0582a62009-12-15 09:54:21 +00001459 }
1460
Leon Clarkee46be812010-01-19 14:06:41 +00001461 // If result_saved is true the result is on top of the stack. If
1462 // result_saved is false the result is in eax.
Steve Blockd0582a62009-12-15 09:54:21 +00001463 bool result_saved = false;
1464
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001465 // Mark all computed expressions that are bound to a key that
1466 // is shadowed by a later occurrence of the same key. For the
1467 // marked expressions, no store code is emitted.
1468 expr->CalculateEmitStore();
1469
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001470 AccessorTable accessor_table(isolate()->zone());
Steve Blockd0582a62009-12-15 09:54:21 +00001471 for (int i = 0; i < expr->properties()->length(); i++) {
1472 ObjectLiteral::Property* property = expr->properties()->at(i);
1473 if (property->IsCompileTimeValue()) continue;
1474
1475 Literal* key = property->key();
1476 Expression* value = property->value();
1477 if (!result_saved) {
1478 __ push(eax); // Save result on the stack
1479 result_saved = true;
1480 }
1481 switch (property->kind()) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001482 case ObjectLiteral::Property::CONSTANT:
1483 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +00001484 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
Steve Blockd0582a62009-12-15 09:54:21 +00001485 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
Leon Clarkee46be812010-01-19 14:06:41 +00001486 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001487 case ObjectLiteral::Property::COMPUTED:
1488 if (key->handle()->IsSymbol()) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001489 if (property->emit_store()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001490 VisitForAccumulatorValue(value);
1491 __ mov(ecx, Immediate(key->handle()));
1492 __ mov(edx, Operand(esp, 0));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001493 Handle<Code> ic = is_classic_mode()
1494 ? isolate()->builtins()->StoreIC_Initialize()
1495 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001496 CallIC(ic, RelocInfo::CODE_TARGET, key->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001497 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1498 } else {
1499 VisitForEffect(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001500 }
Steve Blockd0582a62009-12-15 09:54:21 +00001501 break;
1502 }
Leon Clarkee46be812010-01-19 14:06:41 +00001503 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001504 case ObjectLiteral::Property::PROTOTYPE:
Leon Clarkee46be812010-01-19 14:06:41 +00001505 __ push(Operand(esp, 0)); // Duplicate receiver.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001506 VisitForStackValue(key);
1507 VisitForStackValue(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001508 if (property->emit_store()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001509 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1510 __ CallRuntime(Runtime::kSetProperty, 4);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001511 } else {
1512 __ Drop(3);
1513 }
Steve Blockd0582a62009-12-15 09:54:21 +00001514 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001515 case ObjectLiteral::Property::GETTER:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001516 accessor_table.lookup(key)->second->getter = value;
Steve Blockd0582a62009-12-15 09:54:21 +00001517 break;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001518 case ObjectLiteral::Property::SETTER:
1519 accessor_table.lookup(key)->second->setter = value;
1520 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001521 }
1522 }
Leon Clarkee46be812010-01-19 14:06:41 +00001523
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001524 // Emit code to define accessors, using only a single call to the runtime for
1525 // each pair of corresponding getters and setters.
1526 for (AccessorTable::Iterator it = accessor_table.begin();
1527 it != accessor_table.end();
1528 ++it) {
1529 __ push(Operand(esp, 0)); // Duplicate receiver.
1530 VisitForStackValue(it->first);
1531 EmitAccessor(it->second->getter);
1532 EmitAccessor(it->second->setter);
1533 __ push(Immediate(Smi::FromInt(NONE)));
1534 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
1535 }
1536
Steve Block44f0eee2011-05-26 01:26:41 +01001537 if (expr->has_function()) {
1538 ASSERT(result_saved);
1539 __ push(Operand(esp, 0));
1540 __ CallRuntime(Runtime::kToFastProperties, 1);
1541 }
1542
Leon Clarkee46be812010-01-19 14:06:41 +00001543 if (result_saved) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001544 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001545 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001546 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001547 }
1548}
1549
1550
Leon Clarked91b9f72010-01-27 17:25:45 +00001551void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001552 Comment cmnt(masm_, "[ ArrayLiteral");
Leon Clarkef7060e22010-06-03 12:02:55 +01001553
1554 ZoneList<Expression*>* subexprs = expr->values();
1555 int length = subexprs->length();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001556 Handle<FixedArray> constant_elements = expr->constant_elements();
1557 ASSERT_EQ(2, constant_elements->length());
1558 ElementsKind constant_elements_kind =
1559 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
1560 bool has_constant_fast_elements = constant_elements_kind == FAST_ELEMENTS;
1561 Handle<FixedArrayBase> constant_elements_values(
1562 FixedArrayBase::cast(constant_elements->get(1)));
Leon Clarkef7060e22010-06-03 12:02:55 +01001563
Steve Block3ce2e202009-11-05 08:53:23 +00001564 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00001565 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001566 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001567 __ push(Immediate(constant_elements));
1568 Heap* heap = isolate()->heap();
1569 if (has_constant_fast_elements &&
1570 constant_elements_values->map() == heap->fixed_cow_array_map()) {
1571 // If the elements are already FAST_ELEMENTS, the boilerplate cannot
1572 // change, so it's possible to specialize the stub in advance.
Steve Block44f0eee2011-05-26 01:26:41 +01001573 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001574 FastCloneShallowArrayStub stub(
1575 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
1576 length);
1577 __ CallStub(&stub);
Iain Merrick75681382010-08-19 15:07:18 +01001578 } else if (expr->depth() > 1) {
Leon Clarkee46be812010-01-19 14:06:41 +00001579 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
Iain Merrick75681382010-08-19 15:07:18 +01001580 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
Leon Clarkee46be812010-01-19 14:06:41 +00001581 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001582 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001583 ASSERT(constant_elements_kind == FAST_ELEMENTS ||
1584 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
1585 FLAG_smi_only_arrays);
1586 // If the elements are already FAST_ELEMENTS, the boilerplate cannot
1587 // change, so it's possible to specialize the stub in advance.
1588 FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
1589 ? FastCloneShallowArrayStub::CLONE_ELEMENTS
1590 : FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
1591 FastCloneShallowArrayStub stub(mode, length);
Leon Clarkef7060e22010-06-03 12:02:55 +01001592 __ CallStub(&stub);
Steve Block3ce2e202009-11-05 08:53:23 +00001593 }
1594
1595 bool result_saved = false; // Is the result saved to the stack?
1596
1597 // Emit code to evaluate all the non-constant subexpressions and to store
1598 // them into the newly cloned array.
Leon Clarkef7060e22010-06-03 12:02:55 +01001599 for (int i = 0; i < length; i++) {
Steve Block3ce2e202009-11-05 08:53:23 +00001600 Expression* subexpr = subexprs->at(i);
1601 // If the subexpression is a literal or a simple materialized literal it
1602 // is already set in the cloned array.
1603 if (subexpr->AsLiteral() != NULL ||
1604 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1605 continue;
1606 }
1607
1608 if (!result_saved) {
1609 __ push(eax);
1610 result_saved = true;
1611 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001612 VisitForAccumulatorValue(subexpr);
Steve Block3ce2e202009-11-05 08:53:23 +00001613
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001614 if (constant_elements_kind == FAST_ELEMENTS) {
1615 // Fast-case array literal with ElementsKind of FAST_ELEMENTS, they cannot
1616 // transition and don't need to call the runtime stub.
1617 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1618 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1619 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1620 // Store the subexpression value in the array's elements.
1621 __ mov(FieldOperand(ebx, offset), result_register());
1622 // Update the write barrier for the array store.
1623 __ RecordWriteField(ebx, offset, result_register(), ecx,
1624 kDontSaveFPRegs,
1625 EMIT_REMEMBERED_SET,
1626 INLINE_SMI_CHECK);
1627 } else {
1628 // Store the subexpression value in the array's elements.
1629 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1630 __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
1631 __ mov(ecx, Immediate(Smi::FromInt(i)));
1632 __ mov(edx, Immediate(Smi::FromInt(expr->literal_index())));
1633 StoreArrayLiteralElementStub stub;
1634 __ CallStub(&stub);
1635 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001636
1637 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +00001638 }
1639
Leon Clarkee46be812010-01-19 14:06:41 +00001640 if (result_saved) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001641 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001642 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001643 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001644 }
1645}
1646
1647
Andrei Popescu402d9372010-02-26 13:31:12 +00001648void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1649 Comment cmnt(masm_, "[ Assignment");
Leon Clarkef7060e22010-06-03 12:02:55 +01001650 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1651 // on the left-hand side.
1652 if (!expr->target()->IsValidLeftHandSide()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001653 VisitForEffect(expr->target());
Leon Clarkef7060e22010-06-03 12:02:55 +01001654 return;
1655 }
1656
Andrei Popescu402d9372010-02-26 13:31:12 +00001657 // Left-hand side can only be a property, a global or a (parameter or local)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001658 // slot.
Andrei Popescu402d9372010-02-26 13:31:12 +00001659 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1660 LhsKind assign_type = VARIABLE;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001661 Property* property = expr->target()->AsProperty();
1662 if (property != NULL) {
1663 assign_type = (property->key()->IsPropertyName())
1664 ? NAMED_PROPERTY
1665 : KEYED_PROPERTY;
Andrei Popescu402d9372010-02-26 13:31:12 +00001666 }
1667
1668 // Evaluate LHS expression.
1669 switch (assign_type) {
1670 case VARIABLE:
1671 // Nothing to do here.
1672 break;
1673 case NAMED_PROPERTY:
1674 if (expr->is_compound()) {
1675 // We need the receiver both on the stack and in the accumulator.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001676 VisitForAccumulatorValue(property->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00001677 __ push(result_register());
1678 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001679 VisitForStackValue(property->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00001680 }
1681 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001682 case KEYED_PROPERTY: {
Andrei Popescu402d9372010-02-26 13:31:12 +00001683 if (expr->is_compound()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001684 VisitForStackValue(property->obj());
1685 VisitForAccumulatorValue(property->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00001686 __ mov(edx, Operand(esp, 0));
1687 __ push(eax);
1688 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001689 VisitForStackValue(property->obj());
1690 VisitForStackValue(property->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00001691 }
1692 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001693 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001694 }
1695
Ben Murdoch8b112d22011-06-08 16:22:53 +01001696 // For compound assignments we need another deoptimization point after the
1697 // variable/property load.
Andrei Popescu402d9372010-02-26 13:31:12 +00001698 if (expr->is_compound()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001699 AccumulatorValueContext result_context(this);
1700 { AccumulatorValueContext left_operand_context(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001701 switch (assign_type) {
1702 case VARIABLE:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001703 EmitVariableLoad(expr->target()->AsVariableProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001704 PrepareForBailout(expr->target(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001705 break;
1706 case NAMED_PROPERTY:
1707 EmitNamedPropertyLoad(property);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001708 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001709 break;
1710 case KEYED_PROPERTY:
1711 EmitKeyedPropertyLoad(property);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001712 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001713 break;
1714 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001715 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001716
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001717 Token::Value op = expr->binary_op();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001718 __ push(eax); // Left operand goes on the stack.
1719 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001720
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001721 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1722 ? OVERWRITE_RIGHT
1723 : NO_OVERWRITE;
1724 SetSourcePosition(expr->position() + 1);
1725 if (ShouldInlineSmiCase(op)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001726 EmitInlineSmiBinaryOp(expr->binary_operation(),
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001727 op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001728 mode,
1729 expr->target(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001730 expr->value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001731 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00001732 EmitBinaryOp(expr->binary_operation(), op, mode);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001733 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001734
1735 // Deoptimization point in case the binary operation may have side effects.
1736 PrepareForBailout(expr->binary_operation(), TOS_REG);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001737 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001738 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001739 }
1740
1741 // Record source position before possible IC call.
1742 SetSourcePosition(expr->position());
1743
1744 // Store the value.
1745 switch (assign_type) {
1746 case VARIABLE:
1747 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001748 expr->op());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001749 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1750 context()->Plug(eax);
Andrei Popescu402d9372010-02-26 13:31:12 +00001751 break;
1752 case NAMED_PROPERTY:
1753 EmitNamedPropertyAssignment(expr);
1754 break;
1755 case KEYED_PROPERTY:
1756 EmitKeyedPropertyAssignment(expr);
1757 break;
1758 }
1759}
1760
1761
Leon Clarked91b9f72010-01-27 17:25:45 +00001762void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00001763 SetSourcePosition(prop->position());
1764 Literal* key = prop->key()->AsLiteral();
Steve Block053d10c2011-06-13 19:13:29 +01001765 ASSERT(!key->handle()->IsSmi());
Leon Clarkee46be812010-01-19 14:06:41 +00001766 __ mov(ecx, Immediate(key->handle()));
Steve Block44f0eee2011-05-26 01:26:41 +01001767 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001768 CallIC(ic, RelocInfo::CODE_TARGET, prop->id());
Leon Clarkee46be812010-01-19 14:06:41 +00001769}
1770
1771
Leon Clarked91b9f72010-01-27 17:25:45 +00001772void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00001773 SetSourcePosition(prop->position());
Steve Block44f0eee2011-05-26 01:26:41 +01001774 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001775 CallIC(ic, RelocInfo::CODE_TARGET, prop->id());
Leon Clarkee46be812010-01-19 14:06:41 +00001776}
1777
1778
Ben Murdoch257744e2011-11-30 15:57:28 +00001779void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001780 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001781 OverwriteMode mode,
1782 Expression* left,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001783 Expression* right) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001784 // Do combined smi check of the operands. Left operand is on the
1785 // stack. Right operand is in eax.
Ben Murdoch257744e2011-11-30 15:57:28 +00001786 Label smi_case, done, stub_call;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001787 __ pop(edx);
1788 __ mov(ecx, eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001789 __ or_(eax, edx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001790 JumpPatchSite patch_site(masm_);
Ben Murdoch257744e2011-11-30 15:57:28 +00001791 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001792
1793 __ bind(&stub_call);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001794 __ mov(eax, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +00001795 BinaryOpStub stub(op, mode);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001796 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001797 patch_site.EmitPatchInfo();
Ben Murdoch257744e2011-11-30 15:57:28 +00001798 __ jmp(&done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001799
Ben Murdochb0fe1622011-05-05 13:52:32 +01001800 // Smi case.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001801 __ bind(&smi_case);
1802 __ mov(eax, edx); // Copy left operand in case of a stub call.
1803
1804 switch (op) {
1805 case Token::SAR:
1806 __ SmiUntag(eax);
1807 __ SmiUntag(ecx);
1808 __ sar_cl(eax); // No checks of result necessary
1809 __ SmiTag(eax);
1810 break;
1811 case Token::SHL: {
1812 Label result_ok;
1813 __ SmiUntag(eax);
1814 __ SmiUntag(ecx);
1815 __ shl_cl(eax);
1816 // Check that the *signed* result fits in a smi.
1817 __ cmp(eax, 0xc0000000);
1818 __ j(positive, &result_ok);
1819 __ SmiTag(ecx);
1820 __ jmp(&stub_call);
1821 __ bind(&result_ok);
1822 __ SmiTag(eax);
1823 break;
1824 }
1825 case Token::SHR: {
1826 Label result_ok;
1827 __ SmiUntag(eax);
1828 __ SmiUntag(ecx);
1829 __ shr_cl(eax);
1830 __ test(eax, Immediate(0xc0000000));
1831 __ j(zero, &result_ok);
1832 __ SmiTag(ecx);
1833 __ jmp(&stub_call);
1834 __ bind(&result_ok);
1835 __ SmiTag(eax);
1836 break;
1837 }
1838 case Token::ADD:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001839 __ add(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001840 __ j(overflow, &stub_call);
1841 break;
1842 case Token::SUB:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001843 __ sub(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001844 __ j(overflow, &stub_call);
1845 break;
1846 case Token::MUL: {
1847 __ SmiUntag(eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001848 __ imul(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001849 __ j(overflow, &stub_call);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001850 __ test(eax, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00001851 __ j(not_zero, &done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001852 __ mov(ebx, edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001853 __ or_(ebx, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001854 __ j(negative, &stub_call);
1855 break;
1856 }
1857 case Token::BIT_OR:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001858 __ or_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001859 break;
1860 case Token::BIT_AND:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001861 __ and_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001862 break;
1863 case Token::BIT_XOR:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001864 __ xor_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001865 break;
1866 default:
1867 UNREACHABLE();
1868 }
1869
1870 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001871 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001872}
1873
1874
Ben Murdoch257744e2011-11-30 15:57:28 +00001875void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1876 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001877 OverwriteMode mode) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001878 __ pop(edx);
Ben Murdoch257744e2011-11-30 15:57:28 +00001879 BinaryOpStub stub(op, mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001880 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001881 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001882 patch_site.EmitPatchInfo();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001883 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00001884}
1885
1886
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001887void FullCodeGenerator::EmitAssignment(Expression* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001888 // Invalid left-hand sides are rewritten to have a 'throw
1889 // ReferenceError' on the left-hand side.
1890 if (!expr->IsValidLeftHandSide()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001891 VisitForEffect(expr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001892 return;
1893 }
1894
1895 // Left-hand side can only be a property, a global or a (parameter or local)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001896 // slot.
Leon Clarkef7060e22010-06-03 12:02:55 +01001897 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1898 LhsKind assign_type = VARIABLE;
1899 Property* prop = expr->AsProperty();
1900 if (prop != NULL) {
1901 assign_type = (prop->key()->IsPropertyName())
1902 ? NAMED_PROPERTY
1903 : KEYED_PROPERTY;
1904 }
1905
1906 switch (assign_type) {
1907 case VARIABLE: {
1908 Variable* var = expr->AsVariableProxy()->var();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001909 EffectContext context(this);
1910 EmitVariableAssignment(var, Token::ASSIGN);
Leon Clarkef7060e22010-06-03 12:02:55 +01001911 break;
1912 }
1913 case NAMED_PROPERTY: {
1914 __ push(eax); // Preserve value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001915 VisitForAccumulatorValue(prop->obj());
Leon Clarkef7060e22010-06-03 12:02:55 +01001916 __ mov(edx, eax);
1917 __ pop(eax); // Restore value.
1918 __ mov(ecx, prop->key()->AsLiteral()->handle());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001919 Handle<Code> ic = is_classic_mode()
1920 ? isolate()->builtins()->StoreIC_Initialize()
1921 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001922 CallIC(ic);
Leon Clarkef7060e22010-06-03 12:02:55 +01001923 break;
1924 }
1925 case KEYED_PROPERTY: {
1926 __ push(eax); // Preserve value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001927 VisitForStackValue(prop->obj());
1928 VisitForAccumulatorValue(prop->key());
1929 __ mov(ecx, eax);
1930 __ pop(edx);
Leon Clarkef7060e22010-06-03 12:02:55 +01001931 __ pop(eax); // Restore value.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001932 Handle<Code> ic = is_classic_mode()
1933 ? isolate()->builtins()->KeyedStoreIC_Initialize()
1934 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001935 CallIC(ic);
Leon Clarkef7060e22010-06-03 12:02:55 +01001936 break;
1937 }
1938 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001939 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001940}
1941
1942
Leon Clarked91b9f72010-01-27 17:25:45 +00001943void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001944 Token::Value op) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001945 if (var->IsUnallocated()) {
1946 // Global var, const, or let.
Steve Block3ce2e202009-11-05 08:53:23 +00001947 __ mov(ecx, var->name());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001948 __ mov(edx, GlobalObjectOperand());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001949 Handle<Code> ic = is_classic_mode()
1950 ? isolate()->builtins()->StoreIC_Initialize()
1951 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001952 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
Steve Block3ce2e202009-11-05 08:53:23 +00001953
Steve Block1e0659c2011-05-24 12:43:12 +01001954 } else if (op == Token::INIT_CONST) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001955 // Const initializers need a write barrier.
1956 ASSERT(!var->IsParameter()); // No const parameters.
1957 if (var->IsStackLocal()) {
1958 Label skip;
1959 __ mov(edx, StackOperand(var));
1960 __ cmp(edx, isolate()->factory()->the_hole_value());
1961 __ j(not_equal, &skip);
1962 __ mov(StackOperand(var), eax);
1963 __ bind(&skip);
1964 } else {
1965 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
1966 // Like var declarations, const declarations are hoisted to function
1967 // scope. However, unlike var initializers, const initializers are
1968 // able to drill a hole to that function context, even from inside a
1969 // 'with' context. We thus bypass the normal static scope lookup for
1970 // var->IsContextSlot().
1971 __ push(eax);
1972 __ push(esi);
1973 __ push(Immediate(var->name()));
1974 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
Steve Block1e0659c2011-05-24 12:43:12 +01001975 }
Steve Block1e0659c2011-05-24 12:43:12 +01001976
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001977 } else if (var->mode() == LET && op != Token::INIT_LET) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001978 // Non-initializing assignment to let variable needs a write barrier.
1979 if (var->IsLookupSlot()) {
1980 __ push(eax); // Value.
1981 __ push(esi); // Context.
1982 __ push(Immediate(var->name()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001983 __ push(Immediate(Smi::FromInt(language_mode())));
Ben Murdoch589d6972011-11-30 16:04:58 +00001984 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1985 } else {
1986 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
1987 Label assign;
1988 MemOperand location = VarOperand(var, ecx);
1989 __ mov(edx, location);
1990 __ cmp(edx, isolate()->factory()->the_hole_value());
1991 __ j(not_equal, &assign, Label::kNear);
1992 __ push(Immediate(var->name()));
1993 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1994 __ bind(&assign);
1995 __ mov(location, eax);
1996 if (var->IsContextSlot()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001997 __ mov(edx, eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001998 int offset = Context::SlotOffset(var->index());
1999 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002000 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002001 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002002
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002003 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
2004 // Assignment to var or initializing assignment to let/const
2005 // in harmony mode.
Ben Murdoch589d6972011-11-30 16:04:58 +00002006 if (var->IsStackAllocated() || var->IsContextSlot()) {
2007 MemOperand location = VarOperand(var, ecx);
2008 if (FLAG_debug_code && op == Token::INIT_LET) {
2009 // Check for an uninitialized let binding.
2010 __ mov(edx, location);
2011 __ cmp(edx, isolate()->factory()->the_hole_value());
2012 __ Check(equal, "Let binding re-initialization.");
Steve Block3ce2e202009-11-05 08:53:23 +00002013 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002014 // Perform the assignment.
2015 __ mov(location, eax);
2016 if (var->IsContextSlot()) {
2017 __ mov(edx, eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002018 int offset = Context::SlotOffset(var->index());
2019 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
Ben Murdoch589d6972011-11-30 16:04:58 +00002020 }
2021 } else {
2022 ASSERT(var->IsLookupSlot());
2023 __ push(eax); // Value.
2024 __ push(esi); // Context.
2025 __ push(Immediate(var->name()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002026 __ push(Immediate(Smi::FromInt(language_mode())));
Ben Murdoch589d6972011-11-30 16:04:58 +00002027 __ CallRuntime(Runtime::kStoreContextSlot, 4);
Steve Block3ce2e202009-11-05 08:53:23 +00002028 }
2029 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002030 // Non-initializing assignments to consts are ignored.
Steve Block3ce2e202009-11-05 08:53:23 +00002031}
2032
2033
Leon Clarked91b9f72010-01-27 17:25:45 +00002034void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002035 // Assignment to a property, using a named store IC.
2036 Property* prop = expr->target()->AsProperty();
2037 ASSERT(prop != NULL);
2038 ASSERT(prop->key()->AsLiteral() != NULL);
Steve Block3ce2e202009-11-05 08:53:23 +00002039
Steve Blockd0582a62009-12-15 09:54:21 +00002040 // If the assignment starts a block of assignments to the same object,
2041 // change to slow case to avoid the quadratic behavior of repeatedly
2042 // adding fast properties.
2043 if (expr->starts_initialization_block()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002044 __ push(result_register());
2045 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
Steve Blockd0582a62009-12-15 09:54:21 +00002046 __ CallRuntime(Runtime::kToSlowProperties, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00002047 __ pop(result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00002048 }
2049
Leon Clarkee46be812010-01-19 14:06:41 +00002050 // Record source code position before IC call.
2051 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00002052 __ mov(ecx, prop->key()->AsLiteral()->handle());
Leon Clarke4515c472010-02-03 11:58:03 +00002053 if (expr->ends_initialization_block()) {
2054 __ mov(edx, Operand(esp, 0));
2055 } else {
2056 __ pop(edx);
2057 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002058 Handle<Code> ic = is_classic_mode()
2059 ? isolate()->builtins()->StoreIC_Initialize()
2060 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002061 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
Steve Blockd0582a62009-12-15 09:54:21 +00002062
2063 // If the assignment ends an initialization block, revert to fast case.
2064 if (expr->ends_initialization_block()) {
2065 __ push(eax); // Result of assignment, saved even if not needed.
2066 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
2067 __ CallRuntime(Runtime::kToFastProperties, 1);
2068 __ pop(eax);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002069 __ Drop(1);
Steve Blockd0582a62009-12-15 09:54:21 +00002070 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002071 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2072 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002073}
2074
2075
Leon Clarked91b9f72010-01-27 17:25:45 +00002076void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002077 // Assignment to a property, using a keyed store IC.
2078
2079 // If the assignment starts a block of assignments to the same object,
2080 // change to slow case to avoid the quadratic behavior of repeatedly
2081 // adding fast properties.
2082 if (expr->starts_initialization_block()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002083 __ push(result_register());
2084 // Receiver is now under the key and value.
Steve Blockd0582a62009-12-15 09:54:21 +00002085 __ push(Operand(esp, 2 * kPointerSize));
2086 __ CallRuntime(Runtime::kToSlowProperties, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00002087 __ pop(result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00002088 }
2089
Steve Block6ded16b2010-05-10 14:33:55 +01002090 __ pop(ecx);
2091 if (expr->ends_initialization_block()) {
2092 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
2093 } else {
2094 __ pop(edx);
2095 }
Leon Clarkee46be812010-01-19 14:06:41 +00002096 // Record source code position before IC call.
2097 SetSourcePosition(expr->position());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002098 Handle<Code> ic = is_classic_mode()
2099 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2100 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002101 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
Steve Blockd0582a62009-12-15 09:54:21 +00002102
2103 // If the assignment ends an initialization block, revert to fast case.
2104 if (expr->ends_initialization_block()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002105 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00002106 __ push(eax); // Result of assignment, saved even if not needed.
Steve Block6ded16b2010-05-10 14:33:55 +01002107 __ push(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00002108 __ CallRuntime(Runtime::kToFastProperties, 1);
2109 __ pop(eax);
2110 }
2111
Ben Murdochb0fe1622011-05-05 13:52:32 +01002112 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002113 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002114}
2115
2116
Leon Clarked91b9f72010-01-27 17:25:45 +00002117void FullCodeGenerator::VisitProperty(Property* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002118 Comment cmnt(masm_, "[ Property");
2119 Expression* key = expr->key();
Steve Blockd0582a62009-12-15 09:54:21 +00002120
Leon Clarkee46be812010-01-19 14:06:41 +00002121 if (key->IsPropertyName()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002122 VisitForAccumulatorValue(expr->obj());
Leon Clarkee46be812010-01-19 14:06:41 +00002123 EmitNamedPropertyLoad(expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002124 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002125 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002126 VisitForStackValue(expr->obj());
2127 VisitForAccumulatorValue(expr->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00002128 __ pop(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00002129 EmitKeyedPropertyLoad(expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002130 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002131 }
Steve Blockd0582a62009-12-15 09:54:21 +00002132}
2133
2134
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002135void FullCodeGenerator::CallIC(Handle<Code> code,
2136 RelocInfo::Mode rmode,
2137 unsigned ast_id) {
2138 ic_total_count_++;
2139 __ call(code, rmode, ast_id);
2140}
2141
2142
2143
2144
Leon Clarked91b9f72010-01-27 17:25:45 +00002145void FullCodeGenerator::EmitCallWithIC(Call* expr,
Leon Clarkee46be812010-01-19 14:06:41 +00002146 Handle<Object> name,
2147 RelocInfo::Mode mode) {
Steve Blockd0582a62009-12-15 09:54:21 +00002148 // Code common for calls using the IC.
2149 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00002150 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002151 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002152 for (int i = 0; i < arg_count; i++) {
2153 VisitForStackValue(args->at(i));
2154 }
2155 __ Set(ecx, Immediate(name));
Steve Block3ce2e202009-11-05 08:53:23 +00002156 }
Leon Clarkee46be812010-01-19 14:06:41 +00002157 // Record source position of the IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002158 SetSourcePosition(expr->position());
Ben Murdoch257744e2011-11-30 15:57:28 +00002159 Handle<Code> ic =
Ben Murdoch589d6972011-11-30 16:04:58 +00002160 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002161 CallIC(ic, mode, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002162 RecordJSReturnSite(expr);
Steve Block3ce2e202009-11-05 08:53:23 +00002163 // Restore context register.
2164 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002165 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002166}
2167
2168
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002169void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Ben Murdoch257744e2011-11-30 15:57:28 +00002170 Expression* key) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002171 // Load the key.
2172 VisitForAccumulatorValue(key);
2173
2174 // Swap the name of the function and the receiver on the stack to follow
2175 // the calling convention for call ICs.
2176 __ pop(ecx);
2177 __ push(eax);
2178 __ push(ecx);
2179
2180 // Load the arguments.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002181 ZoneList<Expression*>* args = expr->arguments();
2182 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002183 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002184 for (int i = 0; i < arg_count; i++) {
2185 VisitForStackValue(args->at(i));
2186 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002187 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002188 // Record source position of the IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002189 SetSourcePosition(expr->position());
Ben Murdoch589d6972011-11-30 16:04:58 +00002190 Handle<Code> ic =
2191 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002192 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002193 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002194 RecordJSReturnSite(expr);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002195 // Restore context register.
2196 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002197 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002198}
2199
2200
Ben Murdoch257744e2011-11-30 15:57:28 +00002201void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
Steve Blockd0582a62009-12-15 09:54:21 +00002202 // Code common for calls using the call stub.
2203 ZoneList<Expression*>* args = expr->arguments();
2204 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002205 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002206 for (int i = 0; i < arg_count; i++) {
2207 VisitForStackValue(args->at(i));
2208 }
Steve Block3ce2e202009-11-05 08:53:23 +00002209 }
Steve Blockd0582a62009-12-15 09:54:21 +00002210 // Record source position for debugger.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002211 SetSourcePosition(expr->position());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002212
2213 // Record call targets in unoptimized code, but not in the snapshot.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002214 if (!Serializer::enabled()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002215 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002216 Handle<Object> uninitialized =
2217 TypeFeedbackCells::UninitializedSentinel(isolate());
2218 Handle<JSGlobalPropertyCell> cell =
2219 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
2220 RecordTypeFeedbackCell(expr->id(), cell);
2221 __ mov(ebx, cell);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002222 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002223
Ben Murdoch589d6972011-11-30 16:04:58 +00002224 CallFunctionStub stub(arg_count, flags);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002225 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2226 __ CallStub(&stub, expr->id());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002227
Ben Murdochb0fe1622011-05-05 13:52:32 +01002228 RecordJSReturnSite(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00002229 // Restore context register.
2230 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002231 context()->DropAndPlug(1, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002232}
2233
2234
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002235void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002236 // Push copy of the first argument or undefined if it doesn't exist.
2237 if (arg_count > 0) {
2238 __ push(Operand(esp, arg_count * kPointerSize));
2239 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002240 __ push(Immediate(isolate()->factory()->undefined_value()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002241 }
2242
2243 // Push the receiver of the enclosing function.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002244 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002245 // Push the language mode.
2246 __ push(Immediate(Smi::FromInt(language_mode())));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002247
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002248 // Push the start position of the scope the calls resides in.
2249 __ push(Immediate(Smi::FromInt(scope()->start_position())));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002250
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002251 // Do the runtime call.
2252 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002253}
2254
2255
Leon Clarked91b9f72010-01-27 17:25:45 +00002256void FullCodeGenerator::VisitCall(Call* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002257#ifdef DEBUG
2258 // We want to verify that RecordJSReturnSite gets called on all paths
2259 // through this function. Avoid early returns.
2260 expr->return_is_recorded_ = false;
2261#endif
2262
Steve Blockd0582a62009-12-15 09:54:21 +00002263 Comment cmnt(masm_, "[ Call");
Ben Murdoch589d6972011-11-30 16:04:58 +00002264 Expression* callee = expr->expression();
2265 VariableProxy* proxy = callee->AsVariableProxy();
2266 Property* property = callee->AsProperty();
Steve Blockd0582a62009-12-15 09:54:21 +00002267
Ben Murdoch589d6972011-11-30 16:04:58 +00002268 if (proxy != NULL && proxy->var()->is_possibly_eval()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002269 // In a call to eval, we first call %ResolvePossiblyDirectEval to
Ben Murdoch589d6972011-11-30 16:04:58 +00002270 // resolve the function we need to call and the receiver of the call.
2271 // Then we call the resolved function using the given arguments.
Leon Clarkef7060e22010-06-03 12:02:55 +01002272 ZoneList<Expression*>* args = expr->arguments();
2273 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002274 { PreservePositionScope pos_scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002275 VisitForStackValue(callee);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002276 // Reserved receiver slot.
Steve Block44f0eee2011-05-26 01:26:41 +01002277 __ push(Immediate(isolate()->factory()->undefined_value()));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002278 // Push the arguments.
2279 for (int i = 0; i < arg_count; i++) {
2280 VisitForStackValue(args->at(i));
2281 }
2282
Ben Murdoch589d6972011-11-30 16:04:58 +00002283 // Push a copy of the function (found below the arguments) and
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002284 // resolve eval.
2285 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002286 EmitResolvePossiblyDirectEval(arg_count);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002287
2288 // The runtime call returns a pair of values in eax (function) and
2289 // edx (receiver). Touch up the stack with the right values.
2290 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2291 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002292 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002293 // Record source position for debugger.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002294 SetSourcePosition(expr->position());
Ben Murdoch589d6972011-11-30 16:04:58 +00002295 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002296 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01002297 __ CallStub(&stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002298 RecordJSReturnSite(expr);
Leon Clarkef7060e22010-06-03 12:02:55 +01002299 // Restore context register.
2300 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002301 context()->DropAndPlug(1, eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00002302
2303 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002304 // Push global object as receiver for the call IC.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002305 __ push(GlobalObjectOperand());
Ben Murdoch589d6972011-11-30 16:04:58 +00002306 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2307
2308 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Steve Block59151502010-09-22 15:07:15 +01002309 // Call to a lookup slot (dynamically introduced variable).
2310 Label slow, done;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002311 { PreservePositionScope scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002312 // Generate code for loading from variables potentially shadowed by
2313 // eval-introduced variables.
2314 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002315 }
Steve Block59151502010-09-22 15:07:15 +01002316 __ bind(&slow);
Ben Murdoch589d6972011-11-30 16:04:58 +00002317 // Call the runtime to find the function to call (returned in eax) and
2318 // the object holding it (returned in edx).
Leon Clarkef7060e22010-06-03 12:02:55 +01002319 __ push(context_register());
Ben Murdoch589d6972011-11-30 16:04:58 +00002320 __ push(Immediate(proxy->name()));
Leon Clarkef7060e22010-06-03 12:02:55 +01002321 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2322 __ push(eax); // Function.
2323 __ push(edx); // Receiver.
Steve Block59151502010-09-22 15:07:15 +01002324
Ben Murdoch589d6972011-11-30 16:04:58 +00002325 // If fast case code has been generated, emit code to push the function
2326 // and receiver and have the slow path jump around this code.
Steve Block59151502010-09-22 15:07:15 +01002327 if (done.is_linked()) {
2328 Label call;
Ben Murdoch589d6972011-11-30 16:04:58 +00002329 __ jmp(&call, Label::kNear);
Steve Block59151502010-09-22 15:07:15 +01002330 __ bind(&done);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002331 // Push function.
Steve Block59151502010-09-22 15:07:15 +01002332 __ push(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00002333 // The receiver is implicitly the global receiver. Indicate this by
2334 // passing the hole to the call function stub.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002335 __ push(Immediate(isolate()->factory()->the_hole_value()));
Steve Block59151502010-09-22 15:07:15 +01002336 __ bind(&call);
2337 }
2338
Ben Murdoch589d6972011-11-30 16:04:58 +00002339 // The receiver is either the global receiver or an object found by
2340 // LoadContextSlot. That object could be the hole if the receiver is
2341 // implicitly the global object.
Ben Murdoch257744e2011-11-30 15:57:28 +00002342 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
Ben Murdoch589d6972011-11-30 16:04:58 +00002343
2344 } else if (property != NULL) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002345 { PreservePositionScope scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002346 VisitForStackValue(property->obj());
2347 }
2348 if (property->key()->IsPropertyName()) {
2349 EmitCallWithIC(expr,
2350 property->key()->AsLiteral()->handle(),
2351 RelocInfo::CODE_TARGET);
2352 } else {
2353 EmitKeyedCallWithIC(expr, property->key());
2354 }
2355
2356 } else {
2357 // Call to an arbitrary expression not handled specially above.
2358 { PreservePositionScope scope(masm()->positions_recorder());
2359 VisitForStackValue(callee);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002360 }
Steve Blockd0582a62009-12-15 09:54:21 +00002361 // Load global receiver object.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002362 __ mov(ebx, GlobalObjectOperand());
Steve Blockd0582a62009-12-15 09:54:21 +00002363 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2364 // Emit function call.
Ben Murdoch257744e2011-11-30 15:57:28 +00002365 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
Steve Blockd0582a62009-12-15 09:54:21 +00002366 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002367
2368#ifdef DEBUG
2369 // RecordJSReturnSite should have been called.
2370 ASSERT(expr->return_is_recorded_);
2371#endif
Steve Blockd0582a62009-12-15 09:54:21 +00002372}
2373
2374
Leon Clarked91b9f72010-01-27 17:25:45 +00002375void FullCodeGenerator::VisitCallNew(CallNew* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002376 Comment cmnt(masm_, "[ CallNew");
2377 // According to ECMA-262, section 11.2.2, page 44, the function
2378 // expression in new calls must be evaluated before the
2379 // arguments.
Steve Blockd0582a62009-12-15 09:54:21 +00002380
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002381 // Push constructor on the stack. If it's not a function it's used as
2382 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2383 // ignored.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002384 VisitForStackValue(expr->expression());
Steve Blockd0582a62009-12-15 09:54:21 +00002385
2386 // Push the arguments ("left-to-right") on the stack.
2387 ZoneList<Expression*>* args = expr->arguments();
2388 int arg_count = args->length();
2389 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002390 VisitForStackValue(args->at(i));
Steve Blockd0582a62009-12-15 09:54:21 +00002391 }
2392
2393 // Call the construct call builtin that handles allocation and
2394 // constructor invocation.
2395 SetSourcePosition(expr->position());
2396
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002397 // Load function and argument count into edi and eax.
Steve Block053d10c2011-06-13 19:13:29 +01002398 __ SafeSet(eax, Immediate(arg_count));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002399 __ mov(edi, Operand(esp, arg_count * kPointerSize));
Steve Blockd0582a62009-12-15 09:54:21 +00002400
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002401 // Record call targets in unoptimized code, but not in the snapshot.
2402 CallFunctionFlags flags;
2403 if (!Serializer::enabled()) {
2404 flags = RECORD_CALL_TARGET;
2405 Handle<Object> uninitialized =
2406 TypeFeedbackCells::UninitializedSentinel(isolate());
2407 Handle<JSGlobalPropertyCell> cell =
2408 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
2409 RecordTypeFeedbackCell(expr->id(), cell);
2410 __ mov(ebx, cell);
2411 } else {
2412 flags = NO_CALL_FUNCTION_FLAGS;
2413 }
2414
2415 CallConstructStub stub(flags);
2416 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
2417 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002418 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00002419}
2420
2421
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002422void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2423 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002424 ASSERT(args->length() == 1);
2425
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002426 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002427
2428 Label materialize_true, materialize_false;
2429 Label* if_true = NULL;
2430 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002431 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002432 context()->PrepareTest(&materialize_true, &materialize_false,
2433 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002434
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002435 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002436 __ test(eax, Immediate(kSmiTagMask));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002437 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002438
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002439 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002440}
2441
2442
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002443void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2444 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002445 ASSERT(args->length() == 1);
2446
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002447 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002448
2449 Label materialize_true, materialize_false;
2450 Label* if_true = NULL;
2451 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002452 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002453 context()->PrepareTest(&materialize_true, &materialize_false,
2454 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002455
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002456 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002457 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002458 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002459
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002460 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002461}
2462
2463
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002464void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2465 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002466 ASSERT(args->length() == 1);
2467
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002468 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002469
2470 Label materialize_true, materialize_false;
2471 Label* if_true = NULL;
2472 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002473 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002474 context()->PrepareTest(&materialize_true, &materialize_false,
2475 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002476
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002477 __ JumpIfSmi(eax, if_false);
Steve Block44f0eee2011-05-26 01:26:41 +01002478 __ cmp(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +01002479 __ j(equal, if_true);
2480 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2481 // Undetectable objects behave like undefined when tested with typeof.
2482 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2483 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2484 __ j(not_zero, if_false);
2485 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002486 __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
Leon Clarkef7060e22010-06-03 12:02:55 +01002487 __ j(below, if_false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002488 __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002489 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002490 Split(below_equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002491
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002492 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002493}
2494
2495
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002496void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2497 ZoneList<Expression*>* args = expr->arguments();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002498 ASSERT(args->length() == 1);
2499
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002500 VisitForAccumulatorValue(args->at(0));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002501
2502 Label materialize_true, materialize_false;
2503 Label* if_true = NULL;
2504 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002505 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002506 context()->PrepareTest(&materialize_true, &materialize_false,
2507 &if_true, &if_false, &fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002508
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002509 __ JumpIfSmi(eax, if_false);
2510 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002511 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002512 Split(above_equal, if_true, if_false, fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002513
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002514 context()->Plug(if_true, if_false);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002515}
2516
2517
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002518void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2519 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002520 ASSERT(args->length() == 1);
2521
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002522 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002523
2524 Label materialize_true, materialize_false;
2525 Label* if_true = NULL;
2526 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002527 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002528 context()->PrepareTest(&materialize_true, &materialize_false,
2529 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002530
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002531 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002532 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2533 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2534 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002535 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002536 Split(not_zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002537
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002538 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002539}
2540
2541
Iain Merrick75681382010-08-19 15:07:18 +01002542void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002543 CallRuntime* expr) {
2544 ZoneList<Expression*>* args = expr->arguments();
Iain Merrick75681382010-08-19 15:07:18 +01002545 ASSERT(args->length() == 1);
2546
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002547 VisitForAccumulatorValue(args->at(0));
Iain Merrick75681382010-08-19 15:07:18 +01002548
2549 Label materialize_true, materialize_false;
2550 Label* if_true = NULL;
2551 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002552 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002553 context()->PrepareTest(&materialize_true, &materialize_false,
2554 &if_true, &if_false, &fall_through);
Iain Merrick75681382010-08-19 15:07:18 +01002555
Ben Murdoch8b112d22011-06-08 16:22:53 +01002556 if (FLAG_debug_code) __ AbortIfSmi(eax);
2557
2558 // Check whether this map has already been checked to be safe for default
2559 // valueOf.
2560 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2561 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
2562 1 << Map::kStringWrapperSafeForDefaultValueOf);
2563 __ j(not_zero, if_true);
2564
2565 // Check for fast case object. Return false for slow case objects.
2566 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
2567 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2568 __ cmp(ecx, FACTORY->hash_table_map());
2569 __ j(equal, if_false);
2570
2571 // Look for valueOf symbol in the descriptor array, and indicate false if
2572 // found. The type is not checked, so if it is a transition it is a false
2573 // negative.
Ben Murdoch257744e2011-11-30 15:57:28 +00002574 __ LoadInstanceDescriptors(ebx, ebx);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002575 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
2576 // ebx: descriptor array
2577 // ecx: length of descriptor array
2578 // Calculate the end of the descriptor array.
2579 STATIC_ASSERT(kSmiTag == 0);
2580 STATIC_ASSERT(kSmiTagSize == 1);
2581 STATIC_ASSERT(kPointerSize == 4);
2582 __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
2583 // Calculate location of the first key name.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002584 __ add(ebx,
2585 Immediate(FixedArray::kHeaderSize +
2586 DescriptorArray::kFirstIndex * kPointerSize));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002587 // Loop through all the keys in the descriptor array. If one of these is the
2588 // symbol valueOf the result is false.
2589 Label entry, loop;
2590 __ jmp(&entry);
2591 __ bind(&loop);
2592 __ mov(edx, FieldOperand(ebx, 0));
2593 __ cmp(edx, FACTORY->value_of_symbol());
2594 __ j(equal, if_false);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002595 __ add(ebx, Immediate(kPointerSize));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002596 __ bind(&entry);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002597 __ cmp(ebx, ecx);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002598 __ j(not_equal, &loop);
2599
2600 // Reload map as register ebx was used as temporary above.
2601 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2602
2603 // If a valueOf property is not found on the object check that it's
2604 // prototype is the un-modified String prototype. If not result is false.
2605 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002606 __ JumpIfSmi(ecx, if_false);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002607 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2608 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2609 __ mov(edx,
2610 FieldOperand(edx, GlobalObject::kGlobalContextOffset));
2611 __ cmp(ecx,
2612 ContextOperand(edx,
2613 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2614 __ j(not_equal, if_false);
2615 // Set the bit in the map to indicate that it has been checked safe for
2616 // default valueOf and set true result.
2617 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
2618 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2619 __ jmp(if_true);
2620
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002621 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002622 context()->Plug(if_true, if_false);
Iain Merrick75681382010-08-19 15:07:18 +01002623}
2624
2625
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002626void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
2627 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002628 ASSERT(args->length() == 1);
2629
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002630 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002631
2632 Label materialize_true, materialize_false;
2633 Label* if_true = NULL;
2634 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002635 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002636 context()->PrepareTest(&materialize_true, &materialize_false,
2637 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002638
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002639 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002640 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002641 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002642 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002643
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002644 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002645}
2646
2647
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002648void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2649 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002650 ASSERT(args->length() == 1);
2651
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002652 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002653
2654 Label materialize_true, materialize_false;
2655 Label* if_true = NULL;
2656 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002657 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002658 context()->PrepareTest(&materialize_true, &materialize_false,
2659 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002660
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002661 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002662 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002663 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002664 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002665
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002666 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002667}
2668
2669
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002670void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2671 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002672 ASSERT(args->length() == 1);
2673
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002674 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002675
2676 Label materialize_true, materialize_false;
2677 Label* if_true = NULL;
2678 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002679 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002680 context()->PrepareTest(&materialize_true, &materialize_false,
2681 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002682
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002683 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002684 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002685 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002686 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002687
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002688 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002689}
2690
2691
2692
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002693void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
2694 ASSERT(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002695
2696 Label materialize_true, materialize_false;
2697 Label* if_true = NULL;
2698 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002699 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002700 context()->PrepareTest(&materialize_true, &materialize_false,
2701 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002702
2703 // Get the frame pointer for the calling frame.
2704 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2705
2706 // Skip the arguments adaptor frame if it exists.
2707 Label check_frame_marker;
2708 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2709 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2710 __ j(not_equal, &check_frame_marker);
2711 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2712
2713 // Check the marker in the calling frame.
2714 __ bind(&check_frame_marker);
2715 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2716 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002717 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002718 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002719
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002720 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002721}
2722
2723
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002724void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
2725 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002726 ASSERT(args->length() == 2);
2727
2728 // Load the two objects into registers and perform the comparison.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002729 VisitForStackValue(args->at(0));
2730 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01002731
2732 Label materialize_true, materialize_false;
2733 Label* if_true = NULL;
2734 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002735 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002736 context()->PrepareTest(&materialize_true, &materialize_false,
2737 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002738
2739 __ pop(ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002740 __ cmp(eax, ebx);
2741 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002742 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002743
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002744 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002745}
2746
2747
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002748void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
2749 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002750 ASSERT(args->length() == 1);
2751
2752 // ArgumentsAccessStub expects the key in edx and the formal
2753 // parameter count in eax.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002754 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002755 __ mov(edx, eax);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002756 __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
Leon Clarkef7060e22010-06-03 12:02:55 +01002757 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2758 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002759 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002760}
2761
2762
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002763void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
2764 ASSERT(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002765
2766 Label exit;
2767 // Get the number of formal parameters.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002768 __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
Leon Clarkef7060e22010-06-03 12:02:55 +01002769
2770 // Check if the calling frame is an arguments adaptor frame.
2771 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2772 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2773 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2774 __ j(not_equal, &exit);
2775
2776 // Arguments adaptor case: Read the arguments length from the
2777 // adaptor frame.
2778 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2779
2780 __ bind(&exit);
2781 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002782 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002783}
2784
2785
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002786void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2787 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002788 ASSERT(args->length() == 1);
2789 Label done, null, function, non_function_constructor;
2790
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002791 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002792
2793 // If the object is a smi, we return null.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002794 __ JumpIfSmi(eax, &null);
Leon Clarkef7060e22010-06-03 12:02:55 +01002795
2796 // Check that the object is a JS object but take special care of JS
2797 // functions to make sure they have 'Function' as their class.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002798 // Assume that there are only two callable types, and one of them is at
2799 // either end of the type range for JS object types. Saves extra comparisons.
2800 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002801 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
2802 // Map is now in eax.
Leon Clarkef7060e22010-06-03 12:02:55 +01002803 __ j(below, &null);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002804 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2805 FIRST_SPEC_OBJECT_TYPE + 1);
2806 __ j(equal, &function);
Leon Clarkef7060e22010-06-03 12:02:55 +01002807
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002808 __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
2809 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2810 LAST_SPEC_OBJECT_TYPE - 1);
2811 __ j(equal, &function);
2812 // Assume that there is no larger type.
2813 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01002814
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002815 // Check if the constructor in the map is a JS function.
Leon Clarkef7060e22010-06-03 12:02:55 +01002816 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2817 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2818 __ j(not_equal, &non_function_constructor);
2819
2820 // eax now contains the constructor function. Grab the
2821 // instance class name from there.
2822 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2823 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2824 __ jmp(&done);
2825
2826 // Functions have class 'Function'.
2827 __ bind(&function);
Steve Block44f0eee2011-05-26 01:26:41 +01002828 __ mov(eax, isolate()->factory()->function_class_symbol());
Leon Clarkef7060e22010-06-03 12:02:55 +01002829 __ jmp(&done);
2830
2831 // Objects with a non-function constructor have class 'Object'.
2832 __ bind(&non_function_constructor);
Steve Block44f0eee2011-05-26 01:26:41 +01002833 __ mov(eax, isolate()->factory()->Object_symbol());
Leon Clarkef7060e22010-06-03 12:02:55 +01002834 __ jmp(&done);
2835
2836 // Non-JS objects have class null.
2837 __ bind(&null);
Steve Block44f0eee2011-05-26 01:26:41 +01002838 __ mov(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +01002839
2840 // All done.
2841 __ bind(&done);
2842
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002843 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002844}
2845
2846
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002847void FullCodeGenerator::EmitLog(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002848 // Conditionally generate a log call.
2849 // Args:
2850 // 0 (literal string): The type of logging (corresponds to the flags).
2851 // This is used to determine whether or not to generate the log call.
2852 // 1 (string): Format string. Access the string at argument index 2
2853 // with '%2s' (see Logger::LogRuntime for all the formats).
2854 // 2 (array): Arguments to the format string.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002855 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002856 ASSERT_EQ(args->length(), 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01002857 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002858 VisitForStackValue(args->at(1));
2859 VisitForStackValue(args->at(2));
Leon Clarkef7060e22010-06-03 12:02:55 +01002860 __ CallRuntime(Runtime::kLog, 2);
2861 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002862 // Finally, we're expected to leave a value on the top of the stack.
Steve Block44f0eee2011-05-26 01:26:41 +01002863 __ mov(eax, isolate()->factory()->undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002864 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002865}
2866
2867
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002868void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
2869 ASSERT(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002870
2871 Label slow_allocate_heapnumber;
2872 Label heapnumber_allocated;
2873
2874 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2875 __ jmp(&heapnumber_allocated);
2876
2877 __ bind(&slow_allocate_heapnumber);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002878 // Allocate a heap number.
2879 __ CallRuntime(Runtime::kNumberAlloc, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002880 __ mov(edi, eax);
2881
2882 __ bind(&heapnumber_allocated);
2883
Ben Murdoch8b112d22011-06-08 16:22:53 +01002884 __ PrepareCallCFunction(1, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002885 __ mov(eax, ContextOperand(context_register(), Context::GLOBAL_INDEX));
2886 __ mov(eax, FieldOperand(eax, GlobalObject::kGlobalContextOffset));
2887 __ mov(Operand(esp, 0), eax);
2888 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01002889
2890 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2891 // by computing:
2892 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2893 // This is implemented on both SSE2 and FPU.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002894 if (CpuFeatures::IsSupported(SSE2)) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002895 CpuFeatures::Scope fscope(SSE2);
2896 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002897 __ movd(xmm1, ebx);
2898 __ movd(xmm0, eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002899 __ cvtss2sd(xmm1, xmm1);
Ben Murdoch257744e2011-11-30 15:57:28 +00002900 __ xorps(xmm0, xmm1);
Leon Clarkef7060e22010-06-03 12:02:55 +01002901 __ subsd(xmm0, xmm1);
2902 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2903 } else {
2904 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2905 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2906 Immediate(0x41300000));
2907 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2908 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2909 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2910 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2911 __ fsubp(1);
2912 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2913 }
2914 __ mov(eax, edi);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002915 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002916}
2917
2918
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002919void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002920 // Load the arguments on the stack and call the stub.
2921 SubStringStub stub;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002922 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002923 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002924 VisitForStackValue(args->at(0));
2925 VisitForStackValue(args->at(1));
2926 VisitForStackValue(args->at(2));
Leon Clarkef7060e22010-06-03 12:02:55 +01002927 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002928 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002929}
2930
2931
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002932void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002933 // Load the arguments on the stack and call the stub.
2934 RegExpExecStub stub;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002935 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002936 ASSERT(args->length() == 4);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002937 VisitForStackValue(args->at(0));
2938 VisitForStackValue(args->at(1));
2939 VisitForStackValue(args->at(2));
2940 VisitForStackValue(args->at(3));
Leon Clarkef7060e22010-06-03 12:02:55 +01002941 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002942 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002943}
2944
2945
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002946void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
2947 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002948 ASSERT(args->length() == 1);
2949
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002950 VisitForAccumulatorValue(args->at(0)); // Load the object.
Leon Clarkef7060e22010-06-03 12:02:55 +01002951
Ben Murdoch257744e2011-11-30 15:57:28 +00002952 Label done;
Leon Clarkef7060e22010-06-03 12:02:55 +01002953 // If the object is a smi return the object.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002954 __ JumpIfSmi(eax, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01002955 // If the object is not a value type, return the object.
2956 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
Ben Murdoch257744e2011-11-30 15:57:28 +00002957 __ j(not_equal, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01002958 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2959
2960 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002961 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002962}
2963
2964
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002965void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
2966 ZoneList<Expression*>* args = expr->arguments();
2967 ASSERT(args->length() == 2);
2968 ASSERT_NE(NULL, args->at(1)->AsLiteral());
2969 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle()));
2970
2971 VisitForAccumulatorValue(args->at(0)); // Load the object.
2972
2973 Label runtime, done;
2974 Register object = eax;
2975 Register result = eax;
2976 Register scratch = ecx;
2977
2978#ifdef DEBUG
2979 __ AbortIfSmi(object);
2980 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
2981 __ Assert(equal, "Trying to get date field from non-date.");
2982#endif
2983
2984 if (index->value() == 0) {
2985 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
2986 } else {
2987 if (index->value() < JSDate::kFirstUncachedField) {
2988 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
2989 __ mov(scratch, Operand::StaticVariable(stamp));
2990 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
2991 __ j(not_equal, &runtime, Label::kNear);
2992 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
2993 kPointerSize * index->value()));
2994 __ jmp(&done);
2995 }
2996 __ bind(&runtime);
2997 __ PrepareCallCFunction(2, scratch);
2998 __ mov(Operand(esp, 0), object);
2999 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
3000 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
3001 __ bind(&done);
3002 }
3003 context()->Plug(result);
3004}
3005
3006
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003007void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003008 // Load the arguments on the stack and call the runtime function.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003009 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003010 ASSERT(args->length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003011 VisitForStackValue(args->at(0));
3012 VisitForStackValue(args->at(1));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003013
Ben Murdoch8b112d22011-06-08 16:22:53 +01003014 if (CpuFeatures::IsSupported(SSE2)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003015 MathPowStub stub(MathPowStub::ON_STACK);
Steve Block44f0eee2011-05-26 01:26:41 +01003016 __ CallStub(&stub);
3017 } else {
3018 __ CallRuntime(Runtime::kMath_pow, 2);
3019 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003020 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003021}
3022
3023
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003024void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3025 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003026 ASSERT(args->length() == 2);
3027
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003028 VisitForStackValue(args->at(0)); // Load the object.
3029 VisitForAccumulatorValue(args->at(1)); // Load the value.
Leon Clarkef7060e22010-06-03 12:02:55 +01003030 __ pop(ebx); // eax = value. ebx = object.
3031
Ben Murdoch257744e2011-11-30 15:57:28 +00003032 Label done;
Leon Clarkef7060e22010-06-03 12:02:55 +01003033 // If the object is a smi, return the value.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003034 __ JumpIfSmi(ebx, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01003035
3036 // If the object is not a value type, return the value.
3037 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +00003038 __ j(not_equal, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01003039
3040 // Store the value.
3041 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003042
Leon Clarkef7060e22010-06-03 12:02:55 +01003043 // Update the write barrier. Save the value as it will be
3044 // overwritten by the write barrier code and is needed afterward.
3045 __ mov(edx, eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003046 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
Leon Clarkef7060e22010-06-03 12:02:55 +01003047
3048 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003049 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003050}
3051
3052
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003053void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3054 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003055 ASSERT_EQ(args->length(), 1);
3056
3057 // Load the argument on the stack and call the stub.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003058 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003059
3060 NumberToStringStub stub;
3061 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003062 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003063}
3064
3065
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003066void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3067 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003068 ASSERT(args->length() == 1);
3069
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003070 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003071
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003072 Label done;
3073 StringCharFromCodeGenerator generator(eax, ebx);
3074 generator.GenerateFast(masm_);
Leon Clarkef7060e22010-06-03 12:02:55 +01003075 __ jmp(&done);
3076
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003077 NopRuntimeCallHelper call_helper;
3078 generator.GenerateSlow(masm_, call_helper);
Leon Clarkef7060e22010-06-03 12:02:55 +01003079
3080 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003081 context()->Plug(ebx);
Leon Clarkef7060e22010-06-03 12:02:55 +01003082}
3083
3084
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003085void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3086 ZoneList<Expression*>* args = expr->arguments();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003087 ASSERT(args->length() == 2);
3088
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003089 VisitForStackValue(args->at(0));
3090 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003091
3092 Register object = ebx;
3093 Register index = eax;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003094 Register result = edx;
3095
3096 __ pop(object);
3097
3098 Label need_conversion;
3099 Label index_out_of_range;
3100 Label done;
3101 StringCharCodeAtGenerator generator(object,
3102 index,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003103 result,
3104 &need_conversion,
3105 &need_conversion,
3106 &index_out_of_range,
3107 STRING_INDEX_IS_NUMBER);
3108 generator.GenerateFast(masm_);
3109 __ jmp(&done);
3110
3111 __ bind(&index_out_of_range);
3112 // When the index is out of range, the spec requires us to return
3113 // NaN.
Steve Block44f0eee2011-05-26 01:26:41 +01003114 __ Set(result, Immediate(isolate()->factory()->nan_value()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003115 __ jmp(&done);
3116
3117 __ bind(&need_conversion);
Leon Clarkef7060e22010-06-03 12:02:55 +01003118 // Move the undefined value into the result register, which will
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003119 // trigger conversion.
Steve Block44f0eee2011-05-26 01:26:41 +01003120 __ Set(result, Immediate(isolate()->factory()->undefined_value()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003121 __ jmp(&done);
3122
3123 NopRuntimeCallHelper call_helper;
3124 generator.GenerateSlow(masm_, call_helper);
3125
3126 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003127 context()->Plug(result);
Leon Clarkef7060e22010-06-03 12:02:55 +01003128}
3129
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003130
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003131void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3132 ZoneList<Expression*>* args = expr->arguments();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003133 ASSERT(args->length() == 2);
3134
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003135 VisitForStackValue(args->at(0));
3136 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003137
3138 Register object = ebx;
3139 Register index = eax;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003140 Register scratch = edx;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003141 Register result = eax;
3142
3143 __ pop(object);
3144
3145 Label need_conversion;
3146 Label index_out_of_range;
3147 Label done;
3148 StringCharAtGenerator generator(object,
3149 index,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003150 scratch,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003151 result,
3152 &need_conversion,
3153 &need_conversion,
3154 &index_out_of_range,
3155 STRING_INDEX_IS_NUMBER);
3156 generator.GenerateFast(masm_);
3157 __ jmp(&done);
3158
3159 __ bind(&index_out_of_range);
3160 // When the index is out of range, the spec requires us to return
3161 // the empty string.
Steve Block44f0eee2011-05-26 01:26:41 +01003162 __ Set(result, Immediate(isolate()->factory()->empty_string()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003163 __ jmp(&done);
3164
3165 __ bind(&need_conversion);
3166 // Move smi zero into the result register, which will trigger
3167 // conversion.
3168 __ Set(result, Immediate(Smi::FromInt(0)));
3169 __ jmp(&done);
3170
3171 NopRuntimeCallHelper call_helper;
3172 generator.GenerateSlow(masm_, call_helper);
3173
3174 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003175 context()->Plug(result);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003176}
3177
3178
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003179void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3180 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003181 ASSERT_EQ(2, args->length());
3182
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003183 VisitForStackValue(args->at(0));
3184 VisitForStackValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003185
3186 StringAddStub stub(NO_STRING_ADD_FLAGS);
3187 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003188 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003189}
3190
3191
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003192void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3193 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003194 ASSERT_EQ(2, args->length());
3195
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003196 VisitForStackValue(args->at(0));
3197 VisitForStackValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003198
3199 StringCompareStub stub;
3200 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003201 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003202}
3203
3204
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003205void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003206 // Load the argument on the stack and call the stub.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003207 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3208 TranscendentalCacheStub::TAGGED);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003209 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003210 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003211 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003212 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003213 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003214}
3215
3216
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003217void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003218 // Load the argument on the stack and call the stub.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003219 TranscendentalCacheStub stub(TranscendentalCache::COS,
3220 TranscendentalCacheStub::TAGGED);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003221 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003222 ASSERT(args->length() == 1);
3223 VisitForStackValue(args->at(0));
3224 __ CallStub(&stub);
3225 context()->Plug(eax);
3226}
3227
3228
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003229void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
3230 // Load the argument on the stack and call the stub.
3231 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3232 TranscendentalCacheStub::TAGGED);
3233 ZoneList<Expression*>* args = expr->arguments();
3234 ASSERT(args->length() == 1);
3235 VisitForStackValue(args->at(0));
3236 __ CallStub(&stub);
3237 context()->Plug(eax);
3238}
3239
3240
3241void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003242 // Load the argument on the stack and call the stub.
3243 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3244 TranscendentalCacheStub::TAGGED);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003245 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003246 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003247 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003248 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003249 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003250}
3251
3252
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003253void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003254 // Load the argument on the stack and call the runtime function.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003255 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003256 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003257 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003258 __ CallRuntime(Runtime::kMath_sqrt, 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003259 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003260}
3261
3262
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003263void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3264 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003265 ASSERT(args->length() >= 2);
3266
Ben Murdoch257744e2011-11-30 15:57:28 +00003267 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3268 for (int i = 0; i < arg_count + 1; ++i) {
3269 VisitForStackValue(args->at(i));
Leon Clarkef7060e22010-06-03 12:02:55 +01003270 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003271 VisitForAccumulatorValue(args->last()); // Function.
Leon Clarkef7060e22010-06-03 12:02:55 +01003272
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003273 // Check for proxy.
3274 Label proxy, done;
3275 __ CmpObjectType(eax, JS_FUNCTION_PROXY_TYPE, ebx);
3276 __ j(equal, &proxy);
3277
Ben Murdoch257744e2011-11-30 15:57:28 +00003278 // InvokeFunction requires the function in edi. Move it in there.
3279 __ mov(edi, result_register());
Leon Clarkef7060e22010-06-03 12:02:55 +01003280 ParameterCount count(arg_count);
Ben Murdoch257744e2011-11-30 15:57:28 +00003281 __ InvokeFunction(edi, count, CALL_FUNCTION,
3282 NullCallWrapper(), CALL_AS_METHOD);
Leon Clarkef7060e22010-06-03 12:02:55 +01003283 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003284 __ jmp(&done);
3285
3286 __ bind(&proxy);
3287 __ push(eax);
3288 __ CallRuntime(Runtime::kCall, args->length());
3289 __ bind(&done);
3290
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003291 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003292}
3293
3294
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003295void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003296 // Load the arguments on the stack and call the stub.
3297 RegExpConstructResultStub stub;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003298 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003299 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003300 VisitForStackValue(args->at(0));
3301 VisitForStackValue(args->at(1));
3302 VisitForStackValue(args->at(2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003303 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003304 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003305}
3306
3307
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003308void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
3309 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003310 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003311 VisitForStackValue(args->at(0));
3312 VisitForStackValue(args->at(1));
3313 VisitForStackValue(args->at(2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003314 Label done;
3315 Label slow_case;
3316 Register object = eax;
3317 Register index_1 = ebx;
3318 Register index_2 = ecx;
3319 Register elements = edi;
3320 Register temp = edx;
3321 __ mov(object, Operand(esp, 2 * kPointerSize));
3322 // Fetch the map and check if array is in fast case.
3323 // Check that object doesn't require security checks and
3324 // has no indexed interceptor.
Steve Block44f0eee2011-05-26 01:26:41 +01003325 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3326 __ j(not_equal, &slow_case);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003327 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
3328 KeyedLoadIC::kSlowCaseBitFieldMask);
3329 __ j(not_zero, &slow_case);
3330
3331 // Check the object's elements are in fast case and writable.
3332 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
3333 __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01003334 Immediate(isolate()->factory()->fixed_array_map()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003335 __ j(not_equal, &slow_case);
3336
3337 // Check that both indices are smis.
3338 __ mov(index_1, Operand(esp, 1 * kPointerSize));
3339 __ mov(index_2, Operand(esp, 0));
3340 __ mov(temp, index_1);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003341 __ or_(temp, index_2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003342 __ JumpIfNotSmi(temp, &slow_case);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003343
3344 // Check that both indices are valid.
3345 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003346 __ cmp(temp, index_1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003347 __ j(below_equal, &slow_case);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003348 __ cmp(temp, index_2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003349 __ j(below_equal, &slow_case);
3350
3351 // Bring addresses into index1 and index2.
3352 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
3353 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
3354
3355 // Swap elements. Use object and temp as scratch registers.
3356 __ mov(object, Operand(index_1, 0));
3357 __ mov(temp, Operand(index_2, 0));
3358 __ mov(Operand(index_2, 0), object);
3359 __ mov(Operand(index_1, 0), temp);
3360
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003361 Label no_remembered_set;
3362 __ CheckPageFlag(elements,
3363 temp,
3364 1 << MemoryChunk::SCAN_ON_SCAVENGE,
3365 not_zero,
3366 &no_remembered_set,
3367 Label::kNear);
3368 // Possible optimization: do a check that both values are Smis
3369 // (or them and test against Smi mask.)
Ben Murdochb0fe1622011-05-05 13:52:32 +01003370
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003371 // We are swapping two objects in an array and the incremental marker never
3372 // pauses in the middle of scanning a single object. Therefore the
3373 // incremental marker is not disturbed, so we don't need to call the
3374 // RecordWrite stub that notifies the incremental marker.
3375 __ RememberedSetHelper(elements,
3376 index_1,
3377 temp,
3378 kDontSaveFPRegs,
3379 MacroAssembler::kFallThroughAtEnd);
3380 __ RememberedSetHelper(elements,
3381 index_2,
3382 temp,
3383 kDontSaveFPRegs,
3384 MacroAssembler::kFallThroughAtEnd);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003385
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003386 __ bind(&no_remembered_set);
3387
Ben Murdochb0fe1622011-05-05 13:52:32 +01003388 // We are done. Drop elements from the stack, and return undefined.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003389 __ add(esp, Immediate(3 * kPointerSize));
Steve Block44f0eee2011-05-26 01:26:41 +01003390 __ mov(eax, isolate()->factory()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003391 __ jmp(&done);
3392
3393 __ bind(&slow_case);
Leon Clarkef7060e22010-06-03 12:02:55 +01003394 __ CallRuntime(Runtime::kSwapElements, 3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003395
3396 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003397 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003398}
3399
3400
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003401void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3402 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003403 ASSERT_EQ(2, args->length());
3404
3405 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3406 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3407
3408 Handle<FixedArray> jsfunction_result_caches(
Steve Block44f0eee2011-05-26 01:26:41 +01003409 isolate()->global_context()->jsfunction_result_caches());
Leon Clarkef7060e22010-06-03 12:02:55 +01003410 if (jsfunction_result_caches->length() <= cache_id) {
3411 __ Abort("Attempt to use undefined cache.");
Steve Block44f0eee2011-05-26 01:26:41 +01003412 __ mov(eax, isolate()->factory()->undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003413 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003414 return;
3415 }
3416
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003417 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003418
3419 Register key = eax;
3420 Register cache = ebx;
3421 Register tmp = ecx;
Steve Block59151502010-09-22 15:07:15 +01003422 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003423 __ mov(cache,
3424 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
Steve Block59151502010-09-22 15:07:15 +01003425 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003426 __ mov(cache,
3427 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3428
3429 Label done, not_found;
3430 // tmp now holds finger offset as a smi.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003431 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003432 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3433 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3434 __ j(not_equal, &not_found);
3435
3436 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3437 __ jmp(&done);
3438
3439 __ bind(&not_found);
3440 // Call runtime to perform the lookup.
3441 __ push(cache);
3442 __ push(key);
3443 __ CallRuntime(Runtime::kGetFromCache, 2);
3444
3445 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003446 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003447}
3448
3449
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003450void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
3451 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochbb769b22010-08-11 14:56:33 +01003452 ASSERT_EQ(2, args->length());
3453
3454 Register right = eax;
3455 Register left = ebx;
3456 Register tmp = ecx;
3457
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003458 VisitForStackValue(args->at(0));
3459 VisitForAccumulatorValue(args->at(1));
Ben Murdochbb769b22010-08-11 14:56:33 +01003460 __ pop(left);
3461
3462 Label done, fail, ok;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003463 __ cmp(left, right);
Ben Murdochbb769b22010-08-11 14:56:33 +01003464 __ j(equal, &ok);
3465 // Fail if either is a non-HeapObject.
3466 __ mov(tmp, left);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003467 __ and_(tmp, right);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003468 __ JumpIfSmi(tmp, &fail);
Steve Block44f0eee2011-05-26 01:26:41 +01003469 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
3470 __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
Ben Murdochbb769b22010-08-11 14:56:33 +01003471 __ j(not_equal, &fail);
3472 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3473 __ j(not_equal, &fail);
3474 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3475 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3476 __ j(equal, &ok);
3477 __ bind(&fail);
Steve Block44f0eee2011-05-26 01:26:41 +01003478 __ mov(eax, Immediate(isolate()->factory()->false_value()));
Ben Murdochbb769b22010-08-11 14:56:33 +01003479 __ jmp(&done);
3480 __ bind(&ok);
Steve Block44f0eee2011-05-26 01:26:41 +01003481 __ mov(eax, Immediate(isolate()->factory()->true_value()));
Ben Murdochbb769b22010-08-11 14:56:33 +01003482 __ bind(&done);
3483
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003484 context()->Plug(eax);
Ben Murdochbb769b22010-08-11 14:56:33 +01003485}
3486
3487
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003488void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3489 ZoneList<Expression*>* args = expr->arguments();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003490 ASSERT(args->length() == 1);
3491
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003492 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003493
3494 if (FLAG_debug_code) {
3495 __ AbortIfNotString(eax);
3496 }
3497
3498 Label materialize_true, materialize_false;
3499 Label* if_true = NULL;
3500 Label* if_false = NULL;
3501 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003502 context()->PrepareTest(&materialize_true, &materialize_false,
3503 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003504
3505 __ test(FieldOperand(eax, String::kHashFieldOffset),
3506 Immediate(String::kContainsCachedArrayIndexMask));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003507 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003508 Split(zero, if_true, if_false, fall_through);
3509
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003510 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003511}
3512
3513
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003514void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3515 ZoneList<Expression*>* args = expr->arguments();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003516 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003517 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003518
3519 if (FLAG_debug_code) {
3520 __ AbortIfNotString(eax);
3521 }
3522
3523 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3524 __ IndexFromHash(eax, eax);
3525
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003526 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003527}
3528
3529
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003530void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01003531 Label bailout, done, one_char_separator, long_separator,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003532 non_trivial_array, not_size_one_array, loop,
Ben Murdochb8e0da22011-05-16 14:20:40 +01003533 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003534
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003535 ZoneList<Expression*>* args = expr->arguments();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003536 ASSERT(args->length() == 2);
3537 // We will leave the separator on the stack until the end of the function.
3538 VisitForStackValue(args->at(1));
3539 // Load this to eax (= array)
3540 VisitForAccumulatorValue(args->at(0));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003541 // All aliases of the same register have disjoint lifetimes.
3542 Register array = eax;
Ben Murdochb8e0da22011-05-16 14:20:40 +01003543 Register elements = no_reg; // Will be eax.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003544
Ben Murdochb8e0da22011-05-16 14:20:40 +01003545 Register index = edx;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003546
Ben Murdochb8e0da22011-05-16 14:20:40 +01003547 Register string_length = ecx;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003548
Ben Murdochb8e0da22011-05-16 14:20:40 +01003549 Register string = esi;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003550
3551 Register scratch = ebx;
3552
Ben Murdochb8e0da22011-05-16 14:20:40 +01003553 Register array_length = edi;
3554 Register result_pos = no_reg; // Will be edi.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003555
Ben Murdochb8e0da22011-05-16 14:20:40 +01003556 // Separator operand is already pushed.
3557 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3558 Operand result_operand = Operand(esp, 1 * kPointerSize);
3559 Operand array_length_operand = Operand(esp, 0);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003560 __ sub(esp, Immediate(2 * kPointerSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01003561 __ cld();
3562 // Check that the array is a JSArray
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003563 __ JumpIfSmi(array, &bailout);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003564 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3565 __ j(not_equal, &bailout);
3566
3567 // Check that the array has fast elements.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003568 __ CheckFastElements(scratch, &bailout);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003569
Ben Murdochb8e0da22011-05-16 14:20:40 +01003570 // If the array has length zero, return the empty string.
3571 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003572 __ SmiUntag(array_length);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003573 __ j(not_zero, &non_trivial_array);
Steve Block44f0eee2011-05-26 01:26:41 +01003574 __ mov(result_operand, isolate()->factory()->empty_string());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003575 __ jmp(&done);
3576
Ben Murdochb8e0da22011-05-16 14:20:40 +01003577 // Save the array length.
3578 __ bind(&non_trivial_array);
3579 __ mov(array_length_operand, array_length);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003580
Ben Murdochb8e0da22011-05-16 14:20:40 +01003581 // Save the FixedArray containing array's elements.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003582 // End of array's live range.
Ben Murdochb8e0da22011-05-16 14:20:40 +01003583 elements = array;
3584 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003585 array = no_reg;
3586
3587
Ben Murdochb8e0da22011-05-16 14:20:40 +01003588 // Check that all array elements are sequential ASCII strings, and
3589 // accumulate the sum of their lengths, as a smi-encoded value.
3590 __ Set(index, Immediate(0));
3591 __ Set(string_length, Immediate(0));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003592 // Loop condition: while (index < length).
Ben Murdochb8e0da22011-05-16 14:20:40 +01003593 // Live loop registers: index, array_length, string,
3594 // scratch, string_length, elements.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003595 if (FLAG_debug_code) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003596 __ cmp(index, array_length);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003597 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
3598 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003599 __ bind(&loop);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003600 __ mov(string, FieldOperand(elements,
3601 index,
3602 times_pointer_size,
3603 FixedArray::kHeaderSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003604 __ JumpIfSmi(string, &bailout);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003605 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3606 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3607 __ and_(scratch, Immediate(
3608 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3609 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3610 __ j(not_equal, &bailout);
3611 __ add(string_length,
3612 FieldOperand(string, SeqAsciiString::kLengthOffset));
3613 __ j(overflow, &bailout);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003614 __ add(index, Immediate(1));
3615 __ cmp(index, array_length);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003616 __ j(less, &loop);
3617
3618 // If array_length is 1, return elements[0], a string.
3619 __ cmp(array_length, 1);
3620 __ j(not_equal, &not_size_one_array);
3621 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3622 __ mov(result_operand, scratch);
3623 __ jmp(&done);
3624
3625 __ bind(&not_size_one_array);
3626
3627 // End of array_length live range.
3628 result_pos = array_length;
3629 array_length = no_reg;
3630
3631 // Live registers:
3632 // string_length: Sum of string lengths, as a smi.
3633 // elements: FixedArray of strings.
3634
3635 // Check that the separator is a flat ASCII string.
3636 __ mov(string, separator_operand);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003637 __ JumpIfSmi(string, &bailout);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003638 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3639 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003640 __ and_(scratch, Immediate(
3641 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003642 __ cmp(scratch, ASCII_STRING_TYPE);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003643 __ j(not_equal, &bailout);
3644
Ben Murdochb8e0da22011-05-16 14:20:40 +01003645 // Add (separator length times array_length) - separator length
3646 // to string_length.
3647 __ mov(scratch, separator_operand);
3648 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003649 __ sub(string_length, scratch); // May be negative, temporarily.
Ben Murdochb8e0da22011-05-16 14:20:40 +01003650 __ imul(scratch, array_length_operand);
3651 __ j(overflow, &bailout);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003652 __ add(string_length, scratch);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003653 __ j(overflow, &bailout);
3654
3655 __ shr(string_length, 1);
3656 // Live registers and stack values:
3657 // string_length
3658 // elements
3659 __ AllocateAsciiString(result_pos, string_length, scratch,
3660 index, string, &bailout);
3661 __ mov(result_operand, result_pos);
3662 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3663
3664
3665 __ mov(string, separator_operand);
3666 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset),
3667 Immediate(Smi::FromInt(1)));
3668 __ j(equal, &one_char_separator);
3669 __ j(greater, &long_separator);
3670
3671
3672 // Empty separator case
3673 __ mov(index, Immediate(0));
3674 __ jmp(&loop_1_condition);
3675 // Loop condition: while (index < length).
3676 __ bind(&loop_1);
3677 // Each iteration of the loop concatenates one string to the result.
3678 // Live values in registers:
3679 // index: which element of the elements array we are adding to the result.
3680 // result_pos: the position to which we are currently copying characters.
3681 // elements: the FixedArray of strings we are joining.
3682
3683 // Get string = array[index].
3684 __ mov(string, FieldOperand(elements, index,
3685 times_pointer_size,
3686 FixedArray::kHeaderSize));
3687 __ mov(string_length,
3688 FieldOperand(string, String::kLengthOffset));
3689 __ shr(string_length, 1);
3690 __ lea(string,
3691 FieldOperand(string, SeqAsciiString::kHeaderSize));
3692 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003693 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01003694 __ bind(&loop_1_condition);
3695 __ cmp(index, array_length_operand);
3696 __ j(less, &loop_1); // End while (index < length).
3697 __ jmp(&done);
3698
3699
3700
3701 // One-character separator case
3702 __ bind(&one_char_separator);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003703 // Replace separator with its ASCII character value.
Ben Murdochb8e0da22011-05-16 14:20:40 +01003704 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3705 __ mov_b(separator_operand, scratch);
3706
3707 __ Set(index, Immediate(0));
3708 // Jump into the loop after the code that copies the separator, so the first
3709 // element is not preceded by a separator
3710 __ jmp(&loop_2_entry);
3711 // Loop condition: while (index < length).
3712 __ bind(&loop_2);
3713 // Each iteration of the loop concatenates one string to the result.
3714 // Live values in registers:
3715 // index: which element of the elements array we are adding to the result.
3716 // result_pos: the position to which we are currently copying characters.
3717
3718 // Copy the separator character to the result.
3719 __ mov_b(scratch, separator_operand);
3720 __ mov_b(Operand(result_pos, 0), scratch);
3721 __ inc(result_pos);
3722
3723 __ bind(&loop_2_entry);
3724 // Get string = array[index].
3725 __ mov(string, FieldOperand(elements, index,
3726 times_pointer_size,
3727 FixedArray::kHeaderSize));
3728 __ mov(string_length,
3729 FieldOperand(string, String::kLengthOffset));
3730 __ shr(string_length, 1);
3731 __ lea(string,
3732 FieldOperand(string, SeqAsciiString::kHeaderSize));
3733 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003734 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01003735
3736 __ cmp(index, array_length_operand);
3737 __ j(less, &loop_2); // End while (index < length).
3738 __ jmp(&done);
3739
3740
3741 // Long separator case (separator is more than one character).
3742 __ bind(&long_separator);
3743
3744 __ Set(index, Immediate(0));
3745 // Jump into the loop after the code that copies the separator, so the first
3746 // element is not preceded by a separator
3747 __ jmp(&loop_3_entry);
3748 // Loop condition: while (index < length).
3749 __ bind(&loop_3);
3750 // Each iteration of the loop concatenates one string to the result.
3751 // Live values in registers:
3752 // index: which element of the elements array we are adding to the result.
3753 // result_pos: the position to which we are currently copying characters.
3754
3755 // Copy the separator to the result.
3756 __ mov(string, separator_operand);
3757 __ mov(string_length,
3758 FieldOperand(string, String::kLengthOffset));
3759 __ shr(string_length, 1);
3760 __ lea(string,
3761 FieldOperand(string, SeqAsciiString::kHeaderSize));
3762 __ CopyBytes(string, result_pos, string_length, scratch);
3763
3764 __ bind(&loop_3_entry);
3765 // Get string = array[index].
3766 __ mov(string, FieldOperand(elements, index,
3767 times_pointer_size,
3768 FixedArray::kHeaderSize));
3769 __ mov(string_length,
3770 FieldOperand(string, String::kLengthOffset));
3771 __ shr(string_length, 1);
3772 __ lea(string,
3773 FieldOperand(string, SeqAsciiString::kHeaderSize));
3774 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003775 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01003776
3777 __ cmp(index, array_length_operand);
3778 __ j(less, &loop_3); // End while (index < length).
3779 __ jmp(&done);
3780
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003781
3782 __ bind(&bailout);
Steve Block44f0eee2011-05-26 01:26:41 +01003783 __ mov(result_operand, isolate()->factory()->undefined_value());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003784 __ bind(&done);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003785 __ mov(eax, result_operand);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003786 // Drop temp values from the stack, and restore context register.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003787 __ add(esp, Immediate(3 * kPointerSize));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003788
3789 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3790 context()->Plug(eax);
3791}
3792
3793
Leon Clarked91b9f72010-01-27 17:25:45 +00003794void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003795 Handle<String> name = expr->name();
3796 if (name->length() > 0 && name->Get(0) == '_') {
3797 Comment cmnt(masm_, "[ InlineRuntimeCall");
3798 EmitInlineRuntimeCall(expr);
3799 return;
3800 }
3801
Steve Block3ce2e202009-11-05 08:53:23 +00003802 Comment cmnt(masm_, "[ CallRuntime");
3803 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00003804
Steve Blockd0582a62009-12-15 09:54:21 +00003805 if (expr->is_jsruntime()) {
3806 // Prepare for calling JS runtime function.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003807 __ mov(eax, GlobalObjectOperand());
Steve Blockd0582a62009-12-15 09:54:21 +00003808 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3809 }
Steve Block3ce2e202009-11-05 08:53:23 +00003810
3811 // Push the arguments ("left-to-right").
3812 int arg_count = args->length();
3813 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003814 VisitForStackValue(args->at(i));
Steve Block3ce2e202009-11-05 08:53:23 +00003815 }
3816
Steve Blockd0582a62009-12-15 09:54:21 +00003817 if (expr->is_jsruntime()) {
Leon Clarkee46be812010-01-19 14:06:41 +00003818 // Call the JS runtime function via a call IC.
3819 __ Set(ecx, Immediate(expr->name()));
Ben Murdoch257744e2011-11-30 15:57:28 +00003820 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Ben Murdoch589d6972011-11-30 16:04:58 +00003821 Handle<Code> ic =
3822 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01003823 CallIC(ic, mode, expr->id());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003824 // Restore context register.
Steve Blockd0582a62009-12-15 09:54:21 +00003825 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00003826 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00003827 // Call the C runtime function.
3828 __ CallRuntime(expr->function(), arg_count);
Steve Blockd0582a62009-12-15 09:54:21 +00003829 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003830 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003831}
3832
3833
Leon Clarked91b9f72010-01-27 17:25:45 +00003834void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003835 switch (expr->op()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003836 case Token::DELETE: {
3837 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
Ben Murdoch589d6972011-11-30 16:04:58 +00003838 Property* property = expr->expression()->AsProperty();
3839 VariableProxy* proxy = expr->expression()->AsVariableProxy();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003840
Ben Murdoch589d6972011-11-30 16:04:58 +00003841 if (property != NULL) {
3842 VisitForStackValue(property->obj());
3843 VisitForStackValue(property->key());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003844 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
3845 ? kNonStrictMode : kStrictMode;
3846 __ push(Immediate(Smi::FromInt(strict_mode_flag)));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003847 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003848 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00003849 } else if (proxy != NULL) {
3850 Variable* var = proxy->var();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003851 // Delete of an unqualified identifier is disallowed in strict mode
Ben Murdoch589d6972011-11-30 16:04:58 +00003852 // but "delete this" is allowed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003853 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
Ben Murdoch589d6972011-11-30 16:04:58 +00003854 if (var->IsUnallocated()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003855 __ push(GlobalObjectOperand());
3856 __ push(Immediate(var->name()));
3857 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
3858 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3859 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00003860 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
3861 // Result of deleting non-global variables is false. 'this' is
3862 // not really a variable, though we implement it as one. The
3863 // subexpression does not have side effects.
3864 context()->Plug(var->is_this());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003865 } else {
3866 // Non-global variable. Call the runtime to try to delete from the
3867 // context where the variable was introduced.
3868 __ push(context_register());
3869 __ push(Immediate(var->name()));
3870 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3871 context()->Plug(eax);
3872 }
Steve Block1e0659c2011-05-24 12:43:12 +01003873 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003874 // Result of deleting non-property, non-variable reference is true.
3875 // The subexpression may have side effects.
3876 VisitForEffect(expr->expression());
3877 context()->Plug(true);
Leon Clarkef7060e22010-06-03 12:02:55 +01003878 }
3879 break;
3880 }
3881
Steve Blockd0582a62009-12-15 09:54:21 +00003882 case Token::VOID: {
3883 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
Leon Clarkee46be812010-01-19 14:06:41 +00003884 VisitForEffect(expr->expression());
Steve Block44f0eee2011-05-26 01:26:41 +01003885 context()->Plug(isolate()->factory()->undefined_value());
Steve Blockd0582a62009-12-15 09:54:21 +00003886 break;
3887 }
3888
3889 case Token::NOT: {
3890 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003891 if (context()->IsEffect()) {
3892 // Unary NOT has no side effects so it's only necessary to visit the
3893 // subexpression. Match the optimizing compiler by not branching.
3894 VisitForEffect(expr->expression());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003895 } else if (context()->IsTest()) {
3896 const TestContext* test = TestContext::cast(context());
3897 // The labels are swapped for the recursive call.
3898 VisitForControl(expr->expression(),
3899 test->false_label(),
3900 test->true_label(),
3901 test->fall_through());
3902 context()->Plug(test->true_label(), test->false_label());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003903 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003904 // We handle value contexts explicitly rather than simply visiting
3905 // for control and plugging the control flow into the context,
3906 // because we need to prepare a pair of extra administrative AST ids
3907 // for the optimizing compiler.
3908 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
3909 Label materialize_true, materialize_false, done;
3910 VisitForControl(expr->expression(),
3911 &materialize_false,
3912 &materialize_true,
3913 &materialize_true);
3914 __ bind(&materialize_true);
3915 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
3916 if (context()->IsAccumulatorValue()) {
3917 __ mov(eax, isolate()->factory()->true_value());
3918 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003919 __ Push(isolate()->factory()->true_value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003920 }
3921 __ jmp(&done, Label::kNear);
3922 __ bind(&materialize_false);
3923 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
3924 if (context()->IsAccumulatorValue()) {
3925 __ mov(eax, isolate()->factory()->false_value());
3926 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003927 __ Push(isolate()->factory()->false_value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003928 }
3929 __ bind(&done);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003930 }
Steve Blockd0582a62009-12-15 09:54:21 +00003931 break;
3932 }
3933
3934 case Token::TYPEOF: {
3935 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003936 { StackValueContext context(this);
3937 VisitForTypeofValue(expr->expression());
3938 }
Steve Blockd0582a62009-12-15 09:54:21 +00003939 __ CallRuntime(Runtime::kTypeof, 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003940 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003941 break;
3942 }
3943
Leon Clarked91b9f72010-01-27 17:25:45 +00003944 case Token::ADD: {
3945 Comment cmt(masm_, "[ UnaryOperation (ADD)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003946 VisitForAccumulatorValue(expr->expression());
Leon Clarked91b9f72010-01-27 17:25:45 +00003947 Label no_conversion;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003948 __ JumpIfSmi(result_register(), &no_conversion);
Steve Block1e0659c2011-05-24 12:43:12 +01003949 ToNumberStub convert_stub;
3950 __ CallStub(&convert_stub);
Leon Clarked91b9f72010-01-27 17:25:45 +00003951 __ bind(&no_conversion);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003952 context()->Plug(result_register());
Leon Clarked91b9f72010-01-27 17:25:45 +00003953 break;
3954 }
3955
Ben Murdoch257744e2011-11-30 15:57:28 +00003956 case Token::SUB:
3957 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
Leon Clarke4515c472010-02-03 11:58:03 +00003958 break;
Leon Clarke4515c472010-02-03 11:58:03 +00003959
Ben Murdoch257744e2011-11-30 15:57:28 +00003960 case Token::BIT_NOT:
3961 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
Leon Clarke4515c472010-02-03 11:58:03 +00003962 break;
Leon Clarke4515c472010-02-03 11:58:03 +00003963
Steve Blockd0582a62009-12-15 09:54:21 +00003964 default:
3965 UNREACHABLE();
3966 }
3967}
3968
3969
Ben Murdoch257744e2011-11-30 15:57:28 +00003970void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3971 const char* comment) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003972 Comment cmt(masm_, comment);
3973 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3974 UnaryOverwriteMode overwrite =
3975 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
3976 UnaryOpStub stub(expr->op(), overwrite);
3977 // UnaryOpStub expects the argument to be in the
3978 // accumulator register eax.
3979 VisitForAccumulatorValue(expr->expression());
3980 SetSourcePosition(expr->position());
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01003981 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
Ben Murdoch257744e2011-11-30 15:57:28 +00003982 context()->Plug(eax);
3983}
3984
3985
Leon Clarked91b9f72010-01-27 17:25:45 +00003986void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003987 Comment cmnt(masm_, "[ CountOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003988 SetSourcePosition(expr->position());
3989
Leon Clarkef7060e22010-06-03 12:02:55 +01003990 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3991 // as the left-hand side.
3992 if (!expr->expression()->IsValidLeftHandSide()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003993 VisitForEffect(expr->expression());
Leon Clarkef7060e22010-06-03 12:02:55 +01003994 return;
3995 }
Steve Blockd0582a62009-12-15 09:54:21 +00003996
Leon Clarkee46be812010-01-19 14:06:41 +00003997 // Expression can only be a property, a global or a (parameter or local)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003998 // slot.
Leon Clarkee46be812010-01-19 14:06:41 +00003999 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
4000 LhsKind assign_type = VARIABLE;
4001 Property* prop = expr->expression()->AsProperty();
4002 // In case of a property we use the uninitialized expression context
4003 // of the key to detect a named property.
4004 if (prop != NULL) {
4005 assign_type =
4006 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
4007 }
4008
4009 // Evaluate expression and get value.
4010 if (assign_type == VARIABLE) {
4011 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004012 AccumulatorValueContext context(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004013 EmitVariableLoad(expr->expression()->AsVariableProxy());
Leon Clarkef7060e22010-06-03 12:02:55 +01004014 } else {
Leon Clarkee46be812010-01-19 14:06:41 +00004015 // Reserve space for result of postfix operation.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004016 if (expr->is_postfix() && !context()->IsEffect()) {
Leon Clarkee46be812010-01-19 14:06:41 +00004017 __ push(Immediate(Smi::FromInt(0)));
4018 }
Leon Clarkee46be812010-01-19 14:06:41 +00004019 if (assign_type == NAMED_PROPERTY) {
Andrei Popescu402d9372010-02-26 13:31:12 +00004020 // Put the object both on the stack and in the accumulator.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004021 VisitForAccumulatorValue(prop->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00004022 __ push(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004023 EmitNamedPropertyLoad(prop);
4024 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004025 VisitForStackValue(prop->obj());
4026 VisitForAccumulatorValue(prop->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00004027 __ mov(edx, Operand(esp, 0));
4028 __ push(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004029 EmitKeyedPropertyLoad(prop);
4030 }
Leon Clarkee46be812010-01-19 14:06:41 +00004031 }
4032
Ben Murdochb0fe1622011-05-05 13:52:32 +01004033 // We need a second deoptimization point after loading the value
4034 // in case evaluating the property load my have a side effect.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004035 if (assign_type == VARIABLE) {
4036 PrepareForBailout(expr->expression(), TOS_REG);
4037 } else {
4038 PrepareForBailoutForId(expr->CountId(), TOS_REG);
4039 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004040
Leon Clarked91b9f72010-01-27 17:25:45 +00004041 // Call ToNumber only if operand is not a smi.
Ben Murdoch257744e2011-11-30 15:57:28 +00004042 Label no_conversion;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004043 if (ShouldInlineSmiCase(expr->op())) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004044 __ JumpIfSmi(eax, &no_conversion, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004045 }
Steve Block1e0659c2011-05-24 12:43:12 +01004046 ToNumberStub convert_stub;
4047 __ CallStub(&convert_stub);
Leon Clarked91b9f72010-01-27 17:25:45 +00004048 __ bind(&no_conversion);
Steve Blockd0582a62009-12-15 09:54:21 +00004049
Leon Clarkee46be812010-01-19 14:06:41 +00004050 // Save result for postfix expressions.
4051 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004052 if (!context()->IsEffect()) {
4053 // Save the result on the stack. If we have a named or keyed property
4054 // we store the result under the receiver that is currently on top
4055 // of the stack.
4056 switch (assign_type) {
4057 case VARIABLE:
4058 __ push(eax);
4059 break;
4060 case NAMED_PROPERTY:
4061 __ mov(Operand(esp, kPointerSize), eax);
4062 break;
4063 case KEYED_PROPERTY:
4064 __ mov(Operand(esp, 2 * kPointerSize), eax);
4065 break;
4066 }
Leon Clarkee46be812010-01-19 14:06:41 +00004067 }
Steve Blockd0582a62009-12-15 09:54:21 +00004068 }
Leon Clarkee46be812010-01-19 14:06:41 +00004069
Leon Clarked91b9f72010-01-27 17:25:45 +00004070 // Inline smi case if we are in a loop.
Ben Murdoch257744e2011-11-30 15:57:28 +00004071 Label done, stub_call;
Ben Murdochb0fe1622011-05-05 13:52:32 +01004072 JumpPatchSite patch_site(masm_);
4073
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004074 if (ShouldInlineSmiCase(expr->op())) {
Leon Clarked91b9f72010-01-27 17:25:45 +00004075 if (expr->op() == Token::INC) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004076 __ add(eax, Immediate(Smi::FromInt(1)));
Leon Clarked91b9f72010-01-27 17:25:45 +00004077 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004078 __ sub(eax, Immediate(Smi::FromInt(1)));
Leon Clarked91b9f72010-01-27 17:25:45 +00004079 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004080 __ j(overflow, &stub_call, Label::kNear);
Leon Clarked91b9f72010-01-27 17:25:45 +00004081 // We could eliminate this smi check if we split the code at
4082 // the first smi check before calling ToNumber.
Ben Murdoch257744e2011-11-30 15:57:28 +00004083 patch_site.EmitJumpIfSmi(eax, &done, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004084
Leon Clarked91b9f72010-01-27 17:25:45 +00004085 __ bind(&stub_call);
4086 // Call stub. Undo operation first.
4087 if (expr->op() == Token::INC) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004088 __ sub(eax, Immediate(Smi::FromInt(1)));
Leon Clarked91b9f72010-01-27 17:25:45 +00004089 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004090 __ add(eax, Immediate(Smi::FromInt(1)));
Leon Clarked91b9f72010-01-27 17:25:45 +00004091 }
4092 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004093
4094 // Record position before stub call.
4095 SetSourcePosition(expr->position());
4096
Leon Clarkee46be812010-01-19 14:06:41 +00004097 // Call stub for +1/-1.
Ben Murdochb0fe1622011-05-05 13:52:32 +01004098 __ mov(edx, eax);
4099 __ mov(eax, Immediate(Smi::FromInt(1)));
Ben Murdoch257744e2011-11-30 15:57:28 +00004100 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004101 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004102 patch_site.EmitPatchInfo();
Leon Clarked91b9f72010-01-27 17:25:45 +00004103 __ bind(&done);
Steve Blockd0582a62009-12-15 09:54:21 +00004104
Leon Clarkee46be812010-01-19 14:06:41 +00004105 // Store the value returned in eax.
4106 switch (assign_type) {
4107 case VARIABLE:
4108 if (expr->is_postfix()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004109 // Perform the assignment as if via '='.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004110 { EffectContext context(this);
4111 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4112 Token::ASSIGN);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004113 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4114 context.Plug(eax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004115 }
4116 // For all contexts except EffectContext We have the result on
Leon Clarkee46be812010-01-19 14:06:41 +00004117 // top of the stack.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004118 if (!context()->IsEffect()) {
4119 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004120 }
4121 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01004122 // Perform the assignment as if via '='.
Leon Clarkee46be812010-01-19 14:06:41 +00004123 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004124 Token::ASSIGN);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004125 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4126 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004127 }
Steve Blockd0582a62009-12-15 09:54:21 +00004128 break;
Leon Clarkee46be812010-01-19 14:06:41 +00004129 case NAMED_PROPERTY: {
4130 __ mov(ecx, prop->key()->AsLiteral()->handle());
Leon Clarke4515c472010-02-03 11:58:03 +00004131 __ pop(edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004132 Handle<Code> ic = is_classic_mode()
4133 ? isolate()->builtins()->StoreIC_Initialize()
4134 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004135 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004136 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00004137 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004138 if (!context()->IsEffect()) {
4139 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004140 }
4141 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004142 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004143 }
Steve Blockd0582a62009-12-15 09:54:21 +00004144 break;
4145 }
Leon Clarkee46be812010-01-19 14:06:41 +00004146 case KEYED_PROPERTY: {
Steve Block6ded16b2010-05-10 14:33:55 +01004147 __ pop(ecx);
4148 __ pop(edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004149 Handle<Code> ic = is_classic_mode()
4150 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4151 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004152 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004153 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00004154 if (expr->is_postfix()) {
Steve Block6ded16b2010-05-10 14:33:55 +01004155 // Result is on the stack
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004156 if (!context()->IsEffect()) {
4157 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004158 }
4159 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004160 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004161 }
Steve Blockd0582a62009-12-15 09:54:21 +00004162 break;
4163 }
Steve Block3ce2e202009-11-05 08:53:23 +00004164 }
4165}
4166
4167
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004168void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004169 VariableProxy* proxy = expr->AsVariableProxy();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004170 ASSERT(!context()->IsEffect());
4171 ASSERT(!context()->IsTest());
4172
Ben Murdoch589d6972011-11-30 16:04:58 +00004173 if (proxy != NULL && proxy->var()->IsUnallocated()) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004174 Comment cmnt(masm_, "Global variable");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004175 __ mov(eax, GlobalObjectOperand());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004176 __ mov(ecx, Immediate(proxy->name()));
Steve Block44f0eee2011-05-26 01:26:41 +01004177 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004178 // Use a regular load, not a contextual load, to avoid a reference
4179 // error.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004180 CallIC(ic);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004181 PrepareForBailout(expr, TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004182 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00004183 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Steve Block59151502010-09-22 15:07:15 +01004184 Label done, slow;
4185
4186 // Generate code for loading from variables potentially shadowed
4187 // by eval-introduced variables.
Ben Murdoch589d6972011-11-30 16:04:58 +00004188 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
Steve Block59151502010-09-22 15:07:15 +01004189
4190 __ bind(&slow);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004191 __ push(esi);
4192 __ push(Immediate(proxy->name()));
4193 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004194 PrepareForBailout(expr, TOS_REG);
Steve Block59151502010-09-22 15:07:15 +01004195 __ bind(&done);
4196
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004197 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004198 } else {
4199 // This expression cannot throw a reference error at the top level.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004200 VisitInDuplicateContext(expr);
Steve Block3ce2e202009-11-05 08:53:23 +00004201 }
Steve Block3ce2e202009-11-05 08:53:23 +00004202}
4203
4204
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004205void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004206 Expression* sub_expr,
4207 Handle<String> check) {
4208 Label materialize_true, materialize_false;
4209 Label* if_true = NULL;
4210 Label* if_false = NULL;
4211 Label* fall_through = NULL;
4212 context()->PrepareTest(&materialize_true, &materialize_false,
4213 &if_true, &if_false, &fall_through);
4214
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004215 { AccumulatorValueContext context(this);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004216 VisitForTypeofValue(sub_expr);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004217 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004218 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004219
Steve Block44f0eee2011-05-26 01:26:41 +01004220 if (check->Equals(isolate()->heap()->number_symbol())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004221 __ JumpIfSmi(eax, if_true);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004222 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01004223 isolate()->factory()->heap_number_map());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004224 Split(equal, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004225 } else if (check->Equals(isolate()->heap()->string_symbol())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004226 __ JumpIfSmi(eax, if_false);
4227 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4228 __ j(above_equal, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004229 // Check for undetectable objects => false.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004230 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4231 1 << Map::kIsUndetectable);
4232 Split(zero, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004233 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
4234 __ cmp(eax, isolate()->factory()->true_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004235 __ j(equal, if_true);
Steve Block44f0eee2011-05-26 01:26:41 +01004236 __ cmp(eax, isolate()->factory()->false_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004237 Split(equal, if_true, if_false, fall_through);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004238 } else if (FLAG_harmony_typeof &&
4239 check->Equals(isolate()->heap()->null_symbol())) {
4240 __ cmp(eax, isolate()->factory()->null_value());
4241 Split(equal, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004242 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
4243 __ cmp(eax, isolate()->factory()->undefined_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004244 __ j(equal, if_true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004245 __ JumpIfSmi(eax, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004246 // Check for undetectable objects => true.
4247 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4248 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4249 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4250 Split(not_zero, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004251 } else if (check->Equals(isolate()->heap()->function_symbol())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004252 __ JumpIfSmi(eax, if_false);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004253 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4254 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
4255 __ j(equal, if_true);
4256 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
4257 Split(equal, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004258 } else if (check->Equals(isolate()->heap()->object_symbol())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004259 __ JumpIfSmi(eax, if_false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004260 if (!FLAG_harmony_typeof) {
4261 __ cmp(eax, isolate()->factory()->null_value());
4262 __ j(equal, if_true);
4263 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004264 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004265 __ j(below, if_false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004266 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4267 __ j(above, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004268 // Check for undetectable objects => false.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004269 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4270 1 << Map::kIsUndetectable);
4271 Split(zero, if_true, if_false, fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004272 } else {
4273 if (if_false != fall_through) __ jmp(if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004274 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004275 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004276}
4277
4278
Leon Clarked91b9f72010-01-27 17:25:45 +00004279void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004280 Comment cmnt(masm_, "[ CompareOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004281 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00004282
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004283 // First we try a fast inlined version of the compare when one of
4284 // the operands is a literal.
4285 if (TryLiteralCompare(expr)) return;
4286
Leon Clarkee46be812010-01-19 14:06:41 +00004287 // Always perform the comparison for its control flow. Pack the result
4288 // into the expression's context after the comparison is performed.
Leon Clarkef7060e22010-06-03 12:02:55 +01004289 Label materialize_true, materialize_false;
4290 Label* if_true = NULL;
4291 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004292 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004293 context()->PrepareTest(&materialize_true, &materialize_false,
4294 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004295
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004296 Token::Value op = expr->op();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004297 VisitForStackValue(expr->left());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004298 switch (op) {
Leon Clarkee46be812010-01-19 14:06:41 +00004299 case Token::IN:
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004300 VisitForStackValue(expr->right());
Steve Blockd0582a62009-12-15 09:54:21 +00004301 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004302 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01004303 __ cmp(eax, isolate()->factory()->true_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004304 Split(equal, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004305 break;
Steve Blockd0582a62009-12-15 09:54:21 +00004306
4307 case Token::INSTANCEOF: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004308 VisitForStackValue(expr->right());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004309 InstanceofStub stub(InstanceofStub::kNoFlags);
Steve Blockd0582a62009-12-15 09:54:21 +00004310 __ CallStub(&stub);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004311 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4312 __ test(eax, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004313 // The stub returns 0 for true.
4314 Split(zero, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004315 break;
4316 }
4317
4318 default: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004319 VisitForAccumulatorValue(expr->right());
Steve Blockd0582a62009-12-15 09:54:21 +00004320 Condition cc = no_condition;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004321 switch (op) {
Steve Blockd0582a62009-12-15 09:54:21 +00004322 case Token::EQ_STRICT:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004323 case Token::EQ:
Steve Blockd0582a62009-12-15 09:54:21 +00004324 cc = equal;
Steve Blockd0582a62009-12-15 09:54:21 +00004325 break;
4326 case Token::LT:
4327 cc = less;
Steve Blockd0582a62009-12-15 09:54:21 +00004328 break;
4329 case Token::GT:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004330 cc = greater;
Steve Blockd0582a62009-12-15 09:54:21 +00004331 break;
4332 case Token::LTE:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004333 cc = less_equal;
Steve Blockd0582a62009-12-15 09:54:21 +00004334 break;
4335 case Token::GTE:
4336 cc = greater_equal;
Steve Blockd0582a62009-12-15 09:54:21 +00004337 break;
4338 case Token::IN:
4339 case Token::INSTANCEOF:
4340 default:
4341 UNREACHABLE();
4342 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004343 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00004344
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004345 bool inline_smi_code = ShouldInlineSmiCase(op);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004346 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004347 if (inline_smi_code) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004348 Label slow_case;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004349 __ mov(ecx, edx);
4350 __ or_(ecx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00004351 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004352 __ cmp(edx, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004353 Split(cc, if_true, if_false, NULL);
4354 __ bind(&slow_case);
4355 }
Steve Blockd0582a62009-12-15 09:54:21 +00004356
Ben Murdochb0fe1622011-05-05 13:52:32 +01004357 // Record position and call the compare IC.
4358 SetSourcePosition(expr->position());
4359 Handle<Code> ic = CompareIC::GetUninitialized(op);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004360 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004361 patch_site.EmitPatchInfo();
Ben Murdochb0fe1622011-05-05 13:52:32 +01004362
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004363 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4364 __ test(eax, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004365 Split(cc, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004366 }
4367 }
4368
Leon Clarkee46be812010-01-19 14:06:41 +00004369 // Convert the result of the comparison into one expected for this
4370 // expression's context.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004371 context()->Plug(if_true, if_false);
Steve Blockd0582a62009-12-15 09:54:21 +00004372}
4373
4374
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004375void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4376 Expression* sub_expr,
4377 NilValue nil) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004378 Label materialize_true, materialize_false;
4379 Label* if_true = NULL;
4380 Label* if_false = NULL;
4381 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004382 context()->PrepareTest(&materialize_true, &materialize_false,
4383 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004384
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004385 VisitForAccumulatorValue(sub_expr);
4386 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4387 Handle<Object> nil_value = nil == kNullValue ?
4388 isolate()->factory()->null_value() :
4389 isolate()->factory()->undefined_value();
4390 __ cmp(eax, nil_value);
4391 if (expr->op() == Token::EQ_STRICT) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004392 Split(equal, if_true, if_false, fall_through);
4393 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004394 Handle<Object> other_nil_value = nil == kNullValue ?
4395 isolate()->factory()->undefined_value() :
4396 isolate()->factory()->null_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004397 __ j(equal, if_true);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004398 __ cmp(eax, other_nil_value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004399 __ j(equal, if_true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004400 __ JumpIfSmi(eax, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004401 // It can be an undetectable object.
4402 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4403 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4404 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4405 Split(not_zero, if_true, if_false, fall_through);
4406 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004407 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004408}
4409
4410
Leon Clarked91b9f72010-01-27 17:25:45 +00004411void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004412 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004413 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00004414}
4415
Steve Blockd0582a62009-12-15 09:54:21 +00004416
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004417Register FullCodeGenerator::result_register() {
4418 return eax;
4419}
Leon Clarkee46be812010-01-19 14:06:41 +00004420
4421
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004422Register FullCodeGenerator::context_register() {
4423 return esi;
4424}
4425
4426
Leon Clarked91b9f72010-01-27 17:25:45 +00004427void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
Leon Clarkee46be812010-01-19 14:06:41 +00004428 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4429 __ mov(Operand(ebp, frame_offset), value);
4430}
4431
4432
Leon Clarked91b9f72010-01-27 17:25:45 +00004433void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
Steve Block59151502010-09-22 15:07:15 +01004434 __ mov(dst, ContextOperand(esi, context_index));
Leon Clarkee46be812010-01-19 14:06:41 +00004435}
4436
4437
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004438void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4439 Scope* declaration_scope = scope()->DeclarationScope();
4440 if (declaration_scope->is_global_scope()) {
4441 // Contexts nested in the global context have a canonical empty function
4442 // as their closure, not the anonymous closure containing the global
4443 // code. Pass a smi sentinel and let the runtime look up the empty
4444 // function.
4445 __ push(Immediate(Smi::FromInt(0)));
4446 } else if (declaration_scope->is_eval_scope()) {
4447 // Contexts nested inside eval code have the same closure as the context
4448 // calling eval, not the anonymous closure containing the eval code.
4449 // Fetch it from the context.
4450 __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
4451 } else {
4452 ASSERT(declaration_scope->is_function_scope());
4453 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4454 }
4455}
4456
4457
Leon Clarkee46be812010-01-19 14:06:41 +00004458// ----------------------------------------------------------------------------
4459// Non-local control flow support.
4460
Leon Clarked91b9f72010-01-27 17:25:45 +00004461void FullCodeGenerator::EnterFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00004462 // Cook return address on top of stack (smi encoded Code* delta)
4463 ASSERT(!result_register().is(edx));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004464 __ pop(edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004465 __ sub(edx, Immediate(masm_->CodeObject()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004466 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
4467 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004468 __ SmiTag(edx);
4469 __ push(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00004470 // Store result register while executing finally block.
4471 __ push(result_register());
4472}
4473
4474
Leon Clarked91b9f72010-01-27 17:25:45 +00004475void FullCodeGenerator::ExitFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00004476 ASSERT(!result_register().is(edx));
Leon Clarkee46be812010-01-19 14:06:41 +00004477 __ pop(result_register());
4478 // Uncook return address.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004479 __ pop(edx);
4480 __ SmiUntag(edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004481 __ add(edx, Immediate(masm_->CodeObject()));
4482 __ jmp(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00004483}
4484
4485
4486#undef __
Steve Blockd0582a62009-12-15 09:54:21 +00004487
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004488#define __ ACCESS_MASM(masm())
4489
4490FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4491 int* stack_depth,
4492 int* context_length) {
4493 // The macros used here must preserve the result register.
4494
4495 // Because the handler block contains the context of the finally
4496 // code, we can restore it directly from there for the finally code
4497 // rather than iteratively unwinding contexts via their previous
4498 // links.
4499 __ Drop(*stack_depth); // Down to the handler block.
4500 if (*context_length > 0) {
4501 // Restore the context to its dedicated register and the stack.
4502 __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
4503 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
4504 }
4505 __ PopTryHandler();
4506 __ call(finally_entry_);
4507
4508 *stack_depth = 0;
4509 *context_length = 0;
4510 return previous_;
4511}
4512
4513
4514#undef __
4515
Steve Block3ce2e202009-11-05 08:53:23 +00004516} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01004517
4518#endif // V8_TARGET_ARCH_IA32