OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
101 __ RecordJSReturn(); | 101 __ RecordJSReturn(); |
102 // Do not use the leave instruction here because it is too short to | 102 // Do not use the leave instruction here because it is too short to |
103 // patch with the code required by the debugger. | 103 // patch with the code required by the debugger. |
104 __ mov(esp, ebp); | 104 __ mov(esp, ebp); |
105 __ pop(ebp); | 105 __ pop(ebp); |
106 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 106 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); |
107 } | 107 } |
108 } | 108 } |
109 | 109 |
110 | 110 |
111 void FastCodeGenerator::Move(Location destination, Slot* source) { | 111 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { |
112 switch (destination.type()) { | 112 switch (context) { |
113 case Location::kUninitialized: | 113 case Expression::kUninitialized: |
114 UNREACHABLE(); | 114 UNREACHABLE(); |
115 case Location::kEffect: | 115 case Expression::kEffect: |
116 break; | 116 break; |
117 case Location::kValue: | 117 case Expression::kValue: |
118 __ push(Operand(ebp, SlotOffset(source))); | 118 __ push(Operand(ebp, SlotOffset(source))); |
119 break; | 119 break; |
120 } | 120 } |
121 } | 121 } |
122 | 122 |
123 | 123 |
124 void FastCodeGenerator::Move(Location destination, Literal* expr) { | 124 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { |
125 switch (destination.type()) { | 125 switch (context) { |
126 case Location::kUninitialized: | 126 case Expression::kUninitialized: |
127 UNREACHABLE(); | 127 UNREACHABLE(); |
128 case Location::kEffect: | 128 case Expression::kEffect: |
129 break; | 129 break; |
130 case Location::kValue: | 130 case Expression::kValue: |
131 __ push(Immediate(expr->handle())); | 131 __ push(Immediate(expr->handle())); |
132 break; | 132 break; |
133 } | 133 } |
134 } | 134 } |
135 | 135 |
136 | 136 |
137 void FastCodeGenerator::Move(Slot* destination, Location source) { | 137 void FastCodeGenerator::DropAndMove(Expression::Context context, |
138 switch (source.type()) { | 138 Register source) { |
139 case Location::kUninitialized: // Fall through. | 139 switch (context) { |
140 case Location::kEffect: | 140 case Expression::kUninitialized: |
141 UNREACHABLE(); | 141 UNREACHABLE(); |
142 case Location::kValue: | 142 case Expression::kEffect: |
143 __ pop(Operand(ebp, SlotOffset(destination))); | |
144 break; | |
145 } | |
146 } | |
147 | |
148 | |
149 void FastCodeGenerator::DropAndMove(Location destination, Register source) { | |
150 switch (destination.type()) { | |
151 case Location::kUninitialized: | |
152 UNREACHABLE(); | |
153 case Location::kEffect: | |
154 __ add(Operand(esp), Immediate(kPointerSize)); | 143 __ add(Operand(esp), Immediate(kPointerSize)); |
155 break; | 144 break; |
156 case Location::kValue: | 145 case Expression::kValue: |
157 __ mov(Operand(esp, 0), source); | 146 __ mov(Operand(esp, 0), source); |
158 break; | 147 break; |
159 } | 148 } |
160 } | 149 } |
161 | 150 |
162 | 151 |
163 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 152 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
164 // Call the runtime to declare the globals. | 153 // Call the runtime to declare the globals. |
165 __ push(esi); // The context is the first argument. | 154 __ push(esi); // The context is the first argument. |
166 __ push(Immediate(pairs)); | 155 __ push(Immediate(pairs)); |
167 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); | 156 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); |
168 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 157 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
169 // Return value is ignored. | 158 // Return value is ignored. |
170 } | 159 } |
171 | 160 |
172 | 161 |
173 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 162 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
174 Comment cmnt(masm_, "[ ReturnStatement"); | 163 Comment cmnt(masm_, "[ ReturnStatement"); |
175 SetStatementPosition(stmt); | 164 SetStatementPosition(stmt); |
176 Expression* expr = stmt->expression(); | 165 Expression* expr = stmt->expression(); |
177 // Complete the statement based on the type of the subexpression. | 166 Visit(expr); |
178 if (expr->AsLiteral() != NULL) { | 167 ASSERT_EQ(Expression::kValue, expr->context()); |
179 __ mov(eax, expr->AsLiteral()->handle()); | 168 __ pop(eax); |
William Hesse
2009/10/29 15:15:25
Restore optimization?
Kevin Millikin (Chromium)
2009/10/29 16:36:10
Done.
| |
180 } else { | |
181 Visit(expr); | |
182 Move(eax, expr->location()); | |
183 } | |
184 | 169 |
185 if (FLAG_trace) { | 170 if (FLAG_trace) { |
186 __ push(eax); | 171 __ push(eax); |
187 __ CallRuntime(Runtime::kTraceExit, 1); | 172 __ CallRuntime(Runtime::kTraceExit, 1); |
188 } | 173 } |
189 __ RecordJSReturn(); | 174 __ RecordJSReturn(); |
190 | 175 |
191 // Do not use the leave instruction here because it is too short to | 176 // Do not use the leave instruction here because it is too short to |
192 // patch with the code required by the debugger. | 177 // patch with the code required by the debugger. |
193 __ mov(esp, ebp); | 178 __ mov(esp, ebp); |
194 __ pop(ebp); | 179 __ pop(ebp); |
195 __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); | 180 __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); |
196 } | 181 } |
197 | 182 |
198 | 183 |
199 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 184 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
200 Comment cmnt(masm_, "[ FunctionLiteral"); | 185 Comment cmnt(masm_, "[ FunctionLiteral"); |
201 | 186 |
202 // Build the function boilerplate and instantiate it. | 187 // Build the function boilerplate and instantiate it. |
203 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); | 188 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); |
204 if (HasStackOverflow()) return; | 189 if (HasStackOverflow()) return; |
205 | 190 |
206 ASSERT(boilerplate->IsBoilerplate()); | 191 ASSERT(boilerplate->IsBoilerplate()); |
207 | 192 |
208 // Create a new closure. | 193 // Create a new closure. |
209 __ push(esi); | 194 __ push(esi); |
210 __ push(Immediate(boilerplate)); | 195 __ push(Immediate(boilerplate)); |
211 __ CallRuntime(Runtime::kNewClosure, 2); | 196 __ CallRuntime(Runtime::kNewClosure, 2); |
212 Move(expr->location(), eax); | 197 Move(expr->context(), eax); |
213 } | 198 } |
214 | 199 |
215 | 200 |
216 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 201 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
217 Comment cmnt(masm_, "[ VariableProxy"); | 202 Comment cmnt(masm_, "[ VariableProxy"); |
218 Expression* rewrite = expr->var()->rewrite(); | 203 Expression* rewrite = expr->var()->rewrite(); |
219 if (rewrite == NULL) { | 204 if (rewrite == NULL) { |
220 Comment cmnt(masm_, "Global variable"); | 205 Comment cmnt(masm_, "Global variable"); |
221 // Use inline caching. Variable name is passed in ecx and the global | 206 // Use inline caching. Variable name is passed in ecx and the global |
222 // object on the stack. | 207 // object on the stack. |
223 __ push(CodeGenerator::GlobalObject()); | 208 __ push(CodeGenerator::GlobalObject()); |
224 __ mov(ecx, expr->name()); | 209 __ mov(ecx, expr->name()); |
225 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 210 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
226 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 211 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
227 // By emitting a nop we make sure that we do not have a test eax | 212 // By emitting a nop we make sure that we do not have a test eax |
228 // instruction after the call it is treated specially by the LoadIC code | 213 // instruction after the call it is treated specially by the LoadIC code |
229 // Remember that the assembler may choose to do peephole optimization | 214 // Remember that the assembler may choose to do peephole optimization |
230 // (eg, push/pop elimination). | 215 // (eg, push/pop elimination). |
231 __ nop(); | 216 __ nop(); |
232 | 217 |
233 DropAndMove(expr->location(), eax); | 218 DropAndMove(expr->context(), eax); |
234 } else { | 219 } else { |
235 Comment cmnt(masm_, "Stack slot"); | 220 Comment cmnt(masm_, "Stack slot"); |
236 Move(expr->location(), rewrite->AsSlot()); | 221 Move(expr->context(), rewrite->AsSlot()); |
237 } | 222 } |
238 } | 223 } |
239 | 224 |
240 | 225 |
241 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 226 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
242 Comment cmnt(masm_, "[ RegExp Literal"); | 227 Comment cmnt(masm_, "[ RegExp Literal"); |
243 Label done; | 228 Label done; |
244 // Registers will be used as follows: | 229 // Registers will be used as follows: |
245 // edi = JS function. | 230 // edi = JS function. |
246 // ebx = literals array. | 231 // ebx = literals array. |
247 // eax = regexp literal. | 232 // eax = regexp literal. |
248 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 233 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
249 __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 234 __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
250 int literal_offset = | 235 int literal_offset = |
251 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 236 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
252 __ mov(eax, FieldOperand(ebx, literal_offset)); | 237 __ mov(eax, FieldOperand(ebx, literal_offset)); |
253 __ cmp(eax, Factory::undefined_value()); | 238 __ cmp(eax, Factory::undefined_value()); |
254 __ j(not_equal, &done); | 239 __ j(not_equal, &done); |
255 // Create regexp literal using runtime function | 240 // Create regexp literal using runtime function |
256 // Result will be in eax. | 241 // Result will be in eax. |
257 __ push(ebx); | 242 __ push(ebx); |
258 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 243 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
259 __ push(Immediate(expr->pattern())); | 244 __ push(Immediate(expr->pattern())); |
260 __ push(Immediate(expr->flags())); | 245 __ push(Immediate(expr->flags())); |
261 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 246 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
262 // Label done: | 247 // Label done: |
263 __ bind(&done); | 248 __ bind(&done); |
264 Move(expr->location(), eax); | 249 Move(expr->context(), eax); |
265 } | 250 } |
266 | 251 |
267 | 252 |
268 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 253 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
269 Comment cmnt(masm_, "[ ObjectLiteral"); | 254 Comment cmnt(masm_, "[ ObjectLiteral"); |
270 Label exists; | 255 Label exists; |
271 // Registers will be used as follows: | 256 // Registers will be used as follows: |
272 // edi = JS function. | 257 // edi = JS function. |
273 // ebx = literals array. | 258 // ebx = literals array. |
274 // eax = boilerplate | 259 // eax = boilerplate |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
311 if (!result_saved) { | 296 if (!result_saved) { |
312 __ push(eax); // Save result on the stack | 297 __ push(eax); // Save result on the stack |
313 result_saved = true; | 298 result_saved = true; |
314 } | 299 } |
315 switch (property->kind()) { | 300 switch (property->kind()) { |
316 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through | 301 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through |
317 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 302 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
318 case ObjectLiteral::Property::COMPUTED: | 303 case ObjectLiteral::Property::COMPUTED: |
319 if (key->handle()->IsSymbol()) { | 304 if (key->handle()->IsSymbol()) { |
320 Visit(value); | 305 Visit(value); |
321 Move(eax, value->location()); | 306 ASSERT_EQ(Expression::kValue, value->context()); |
307 __ pop(eax); | |
322 __ mov(ecx, Immediate(key->handle())); | 308 __ mov(ecx, Immediate(key->handle())); |
323 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 309 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
324 __ call(ic, RelocInfo::CODE_TARGET); | 310 __ call(ic, RelocInfo::CODE_TARGET); |
325 // StoreIC leaves the receiver on the stack. | 311 // StoreIC leaves the receiver on the stack. |
326 break; | 312 break; |
327 } | 313 } |
328 // fall through | 314 // fall through |
329 case ObjectLiteral::Property::PROTOTYPE: | 315 case ObjectLiteral::Property::PROTOTYPE: |
330 __ push(eax); | 316 __ push(eax); |
331 Visit(key); | 317 Visit(key); |
332 ASSERT(key->location().is_value()); | 318 ASSERT_EQ(Expression::kValue, key->context()); |
333 Visit(value); | 319 Visit(value); |
334 ASSERT(value->location().is_value()); | 320 ASSERT_EQ(Expression::kValue, value->context()); |
335 __ CallRuntime(Runtime::kSetProperty, 3); | 321 __ CallRuntime(Runtime::kSetProperty, 3); |
336 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | 322 __ mov(eax, Operand(esp, 0)); // Restore result into eax. |
337 break; | 323 break; |
338 case ObjectLiteral::Property::SETTER: // fall through | 324 case ObjectLiteral::Property::SETTER: // fall through |
339 case ObjectLiteral::Property::GETTER: | 325 case ObjectLiteral::Property::GETTER: |
340 __ push(eax); | 326 __ push(eax); |
341 Visit(key); | 327 Visit(key); |
342 ASSERT(key->location().is_value()); | 328 ASSERT_EQ(Expression::kValue, key->context()); |
343 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? | 329 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? |
344 Smi::FromInt(1) : | 330 Smi::FromInt(1) : |
345 Smi::FromInt(0))); | 331 Smi::FromInt(0))); |
346 Visit(value); | 332 Visit(value); |
347 ASSERT(value->location().is_value()); | 333 ASSERT_EQ(Expression::kValue, value->context()); |
348 __ CallRuntime(Runtime::kDefineAccessor, 4); | 334 __ CallRuntime(Runtime::kDefineAccessor, 4); |
349 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | 335 __ mov(eax, Operand(esp, 0)); // Restore result into eax. |
350 break; | 336 break; |
351 default: UNREACHABLE(); | 337 default: UNREACHABLE(); |
352 } | 338 } |
353 } | 339 } |
354 switch (expr->location().type()) { | 340 switch (expr->context()) { |
355 case Location::kUninitialized: | 341 case Expression::kUninitialized: |
356 UNREACHABLE(); | 342 UNREACHABLE(); |
357 case Location::kEffect: | 343 case Expression::kEffect: |
358 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); | 344 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); |
359 break; | 345 break; |
360 case Location::kValue: | 346 case Expression::kValue: |
361 if (!result_saved) __ push(eax); | 347 if (!result_saved) __ push(eax); |
362 break; | 348 break; |
363 } | 349 } |
364 } | 350 } |
365 | 351 |
366 | 352 |
367 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 353 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
368 Comment cmnt(masm_, "[ ArrayLiteral"); | 354 Comment cmnt(masm_, "[ ArrayLiteral"); |
369 Label make_clone; | 355 Label make_clone; |
370 | 356 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
405 if (subexpr->AsLiteral() != NULL || | 391 if (subexpr->AsLiteral() != NULL || |
406 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 392 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
407 continue; | 393 continue; |
408 } | 394 } |
409 | 395 |
410 if (!result_saved) { | 396 if (!result_saved) { |
411 __ push(eax); | 397 __ push(eax); |
412 result_saved = true; | 398 result_saved = true; |
413 } | 399 } |
414 Visit(subexpr); | 400 Visit(subexpr); |
415 ASSERT(subexpr->location().is_value()); | 401 ASSERT_EQ(Expression::kValue, subexpr->context()); |
416 | 402 |
417 // Store the subexpression value in the array's elements. | 403 // Store the subexpression value in the array's elements. |
418 __ pop(eax); // Subexpression value. | 404 __ pop(eax); // Subexpression value. |
419 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. | 405 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. |
420 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); | 406 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
421 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 407 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
422 __ mov(FieldOperand(ebx, offset), eax); | 408 __ mov(FieldOperand(ebx, offset), eax); |
423 | 409 |
424 // Update the write barrier for the array store. | 410 // Update the write barrier for the array store. |
425 __ RecordWrite(ebx, offset, eax, ecx); | 411 __ RecordWrite(ebx, offset, eax, ecx); |
426 } | 412 } |
427 | 413 |
428 switch (expr->location().type()) { | 414 switch (expr->context()) { |
429 case Location::kUninitialized: | 415 case Expression::kUninitialized: |
430 UNREACHABLE(); | 416 UNREACHABLE(); |
431 case Location::kEffect: | 417 case Expression::kEffect: |
432 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); | 418 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); |
433 break; | 419 break; |
434 case Location::kValue: | 420 case Expression::kValue: |
435 if (!result_saved) __ push(eax); | 421 if (!result_saved) __ push(eax); |
436 break; | 422 break; |
437 } | 423 } |
438 } | 424 } |
439 | 425 |
440 | 426 |
441 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 427 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
442 Comment cmnt(masm_, "[ Assignment"); | 428 Comment cmnt(masm_, "[ Assignment"); |
443 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 429 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
444 | 430 |
445 // Left-hand side can only be a global or a (parameter or local) slot. | 431 // Left-hand side can only be a global or a (parameter or local) slot. |
446 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 432 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
447 ASSERT(var != NULL); | 433 ASSERT(var != NULL); |
448 ASSERT(var->is_global() || var->slot() != NULL); | 434 ASSERT(var->is_global() || var->slot() != NULL); |
449 | 435 |
450 Expression* rhs = expr->value(); | 436 Expression* rhs = expr->value(); |
451 if (var->is_global()) { | 437 if (var->is_global()) { |
452 // Assignment to a global variable, use inline caching. Right-hand-side | 438 // Assignment to a global variable, use inline caching. Right-hand-side |
453 // value is passed in eax, variable name in ecx, and the global object | 439 // value is passed in eax, variable name in ecx, and the global object |
454 // on the stack. | 440 // on the stack. |
455 | 441 |
456 // Code for the right-hand-side expression depends on its type. | 442 // Code for the right-hand-side expression depends on its type. |
457 if (rhs->AsLiteral() != NULL) { | 443 if (rhs->AsLiteral() != NULL) { |
458 __ mov(eax, rhs->AsLiteral()->handle()); | 444 __ mov(eax, rhs->AsLiteral()->handle()); |
459 } else { | 445 } else { |
460 ASSERT(rhs->location().is_value()); | 446 ASSERT_EQ(Expression::kValue, rhs->context()); |
461 Visit(rhs); | 447 Visit(rhs); |
462 __ pop(eax); | 448 __ pop(eax); |
463 } | 449 } |
464 __ mov(ecx, var->name()); | 450 __ mov(ecx, var->name()); |
465 __ push(CodeGenerator::GlobalObject()); | 451 __ push(CodeGenerator::GlobalObject()); |
466 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 452 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
467 __ call(ic, RelocInfo::CODE_TARGET); | 453 __ call(ic, RelocInfo::CODE_TARGET); |
468 // Overwrite the global object on the stack with the result if needed. | 454 // Overwrite the global object on the stack with the result if needed. |
469 DropAndMove(expr->location(), eax); | 455 DropAndMove(expr->context(), eax); |
470 } else { | 456 } else { |
471 // Local or parameter assignment. | 457 // Local or parameter assignment. |
472 | 458 |
473 // Code for the right-hand side expression depends on its type. | 459 // Code for the right-hand side expression depends on its type. |
474 if (rhs->AsLiteral() != NULL) { | 460 if (rhs->AsLiteral() != NULL) { |
475 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | 461 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a |
476 // discarded result. Always perform the assignment. | 462 // discarded result. Always perform the assignment. |
477 __ mov(eax, rhs->AsLiteral()->handle()); | 463 __ mov(eax, rhs->AsLiteral()->handle()); |
478 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 464 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
479 Move(expr->location(), eax); | 465 Move(expr->context(), eax); |
480 } else { | 466 } else { |
481 ASSERT(rhs->location().is_value()); | 467 ASSERT_EQ(Expression::kValue, rhs->context()); |
482 Visit(rhs); | 468 Visit(rhs); |
483 switch (expr->location().type()) { | 469 switch (expr->context()) { |
484 case Location::kUninitialized: | 470 case Expression::kUninitialized: |
485 UNREACHABLE(); | 471 UNREACHABLE(); |
486 case Location::kEffect: | 472 case Expression::kEffect: |
487 // Case 'var = temp'. Discard right-hand-side temporary. | 473 // Case 'var = temp'. Discard right-hand-side temporary. |
488 Move(var->slot(), rhs->location()); | 474 __ pop(Operand(ebp, SlotOffset(var->slot()))); |
489 break; | 475 break; |
490 case Location::kValue: | 476 case Expression::kValue: |
491 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 477 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
492 // temporary on the stack. | 478 // temporary on the stack. |
493 __ mov(eax, Operand(esp, 0)); | 479 __ mov(eax, Operand(esp, 0)); |
494 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 480 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
495 break; | 481 break; |
496 } | 482 } |
497 } | 483 } |
498 } | 484 } |
499 } | 485 } |
500 | 486 |
(...skipping 23 matching lines...) Expand all Loading... | |
524 // Do a KEYED property load. | 510 // Do a KEYED property load. |
525 Visit(expr->key()); | 511 Visit(expr->key()); |
526 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 512 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
527 __ call(ic, RelocInfo::CODE_TARGET); | 513 __ call(ic, RelocInfo::CODE_TARGET); |
528 // By emitting a nop we make sure that we do not have a "test eax,..." | 514 // By emitting a nop we make sure that we do not have a "test eax,..." |
529 // instruction after the call it is treated specially by the LoadIC code. | 515 // instruction after the call it is treated specially by the LoadIC code. |
530 __ nop(); | 516 __ nop(); |
531 // Drop key left on the stack by IC. | 517 // Drop key left on the stack by IC. |
532 __ add(Operand(esp), Immediate(kPointerSize)); | 518 __ add(Operand(esp), Immediate(kPointerSize)); |
533 } | 519 } |
534 switch (expr->location().type()) { | 520 DropAndMove(expr->context(), eax); |
535 case Location::kUninitialized: | |
536 UNREACHABLE(); | |
537 case Location::kValue: | |
538 __ mov(Operand(esp, 0), eax); | |
539 break; | |
540 case Location::kEffect: | |
541 __ add(Operand(esp), Immediate(kPointerSize)); | |
542 break; | |
543 } | |
544 } | 521 } |
545 | 522 |
546 | 523 |
547 void FastCodeGenerator::VisitCall(Call* expr) { | 524 void FastCodeGenerator::VisitCall(Call* expr) { |
548 Expression* fun = expr->expression(); | 525 Expression* fun = expr->expression(); |
549 ZoneList<Expression*>* args = expr->arguments(); | 526 ZoneList<Expression*>* args = expr->arguments(); |
550 Variable* var = fun->AsVariableProxy()->AsVariable(); | 527 Variable* var = fun->AsVariableProxy()->AsVariable(); |
551 ASSERT(var != NULL && !var->is_this() && var->is_global()); | 528 ASSERT(var != NULL && !var->is_this() && var->is_global()); |
552 ASSERT(!var->is_possibly_eval()); | 529 ASSERT(!var->is_possibly_eval()); |
553 | 530 |
554 __ push(Immediate(var->name())); | 531 __ push(Immediate(var->name())); |
555 // Push global object (receiver). | 532 // Push global object (receiver). |
556 __ push(CodeGenerator::GlobalObject()); | 533 __ push(CodeGenerator::GlobalObject()); |
557 int arg_count = args->length(); | 534 int arg_count = args->length(); |
558 for (int i = 0; i < arg_count; i++) { | 535 for (int i = 0; i < arg_count; i++) { |
559 Visit(args->at(i)); | 536 Visit(args->at(i)); |
560 ASSERT(args->at(i)->location().is_value()); | 537 ASSERT_EQ(Expression::kValue, args->at(i)->context()); |
561 } | 538 } |
562 // Record source position for debugger | 539 // Record source position for debugger |
563 SetSourcePosition(expr->position()); | 540 SetSourcePosition(expr->position()); |
564 // Call the IC initialization code. | 541 // Call the IC initialization code. |
565 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 542 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
566 NOT_IN_LOOP); | 543 NOT_IN_LOOP); |
567 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 544 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
568 // Restore context register. | 545 // Restore context register. |
569 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 546 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
570 // Discard the function left on TOS. | 547 // Discard the function left on TOS. |
571 DropAndMove(expr->location(), eax); | 548 DropAndMove(expr->context(), eax); |
572 } | 549 } |
573 | 550 |
574 | 551 |
575 void FastCodeGenerator::VisitCallNew(CallNew* node) { | 552 void FastCodeGenerator::VisitCallNew(CallNew* expr) { |
576 Comment cmnt(masm_, "[ CallNew"); | 553 Comment cmnt(masm_, "[ CallNew"); |
577 // According to ECMA-262, section 11.2.2, page 44, the function | 554 // According to ECMA-262, section 11.2.2, page 44, the function |
578 // expression in new calls must be evaluated before the | 555 // expression in new calls must be evaluated before the |
579 // arguments. | 556 // arguments. |
580 // Push function on the stack. | 557 // Push function on the stack. |
581 Visit(node->expression()); | 558 Visit(expr->expression()); |
582 ASSERT(node->expression()->location().is_value()); | 559 ASSERT_EQ(Expression::kValue, expr->expression()->context()); |
583 | 560 |
584 // Push global object (receiver). | 561 // Push global object (receiver). |
585 __ push(CodeGenerator::GlobalObject()); | 562 __ push(CodeGenerator::GlobalObject()); |
586 | 563 |
587 // Push the arguments ("left-to-right") on the stack. | 564 // Push the arguments ("left-to-right") on the stack. |
588 ZoneList<Expression*>* args = node->arguments(); | 565 ZoneList<Expression*>* args = expr->arguments(); |
589 int arg_count = args->length(); | 566 int arg_count = args->length(); |
590 for (int i = 0; i < arg_count; i++) { | 567 for (int i = 0; i < arg_count; i++) { |
591 Visit(args->at(i)); | 568 Visit(args->at(i)); |
592 ASSERT(args->at(i)->location().is_value()); | 569 ASSERT_EQ(Expression::kValue, args->at(i)->context()); |
593 // If location is value, it is already on the stack, | 570 // If location is value, it is already on the stack, |
594 // so nothing to do here. | 571 // so nothing to do here. |
595 } | 572 } |
596 | 573 |
597 // Call the construct call builtin that handles allocation and | 574 // Call the construct call builtin that handles allocation and |
598 // constructor invocation. | 575 // constructor invocation. |
599 SetSourcePosition(node->position()); | 576 SetSourcePosition(expr->position()); |
600 | 577 |
601 // Load function, arg_count into edi and eax. | 578 // Load function, arg_count into edi and eax. |
602 __ Set(eax, Immediate(arg_count)); | 579 __ Set(eax, Immediate(arg_count)); |
603 // Function is in esp[arg_count + 1]. | 580 // Function is in esp[arg_count + 1]. |
604 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); | 581 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); |
605 | 582 |
606 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); | 583 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); |
607 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); | 584 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); |
608 | 585 |
609 // Replace function on TOS with result in eax, or pop it. | 586 // Replace function on TOS with result in eax, or pop it. |
610 DropAndMove(node->location(), eax); | 587 DropAndMove(expr->context(), eax); |
611 } | 588 } |
612 | 589 |
613 | 590 |
614 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 591 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
615 Comment cmnt(masm_, "[ CallRuntime"); | 592 Comment cmnt(masm_, "[ CallRuntime"); |
616 ZoneList<Expression*>* args = expr->arguments(); | 593 ZoneList<Expression*>* args = expr->arguments(); |
617 Runtime::Function* function = expr->function(); | 594 Runtime::Function* function = expr->function(); |
618 | 595 |
619 ASSERT(function != NULL); | 596 ASSERT(function != NULL); |
620 | 597 |
621 // Push the arguments ("left-to-right"). | 598 // Push the arguments ("left-to-right"). |
622 int arg_count = args->length(); | 599 int arg_count = args->length(); |
623 for (int i = 0; i < arg_count; i++) { | 600 for (int i = 0; i < arg_count; i++) { |
624 Visit(args->at(i)); | 601 Visit(args->at(i)); |
625 ASSERT(args->at(i)->location().is_value()); | 602 ASSERT_EQ(Expression::kValue, args->at(i)->context()); |
626 } | 603 } |
627 | 604 |
628 __ CallRuntime(function, arg_count); | 605 __ CallRuntime(function, arg_count); |
629 Move(expr->location(), eax); | 606 Move(expr->context(), eax); |
630 } | 607 } |
631 | 608 |
632 | 609 |
633 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 610 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
634 switch (expr->op()) { | 611 switch (expr->op()) { |
635 case Token::COMMA: | 612 case Token::COMMA: |
636 ASSERT(expr->left()->location().is_effect()); | 613 ASSERT_EQ(Expression::kValue, expr->left()->context()); |
637 ASSERT_EQ(expr->right()->location().type(), expr->location().type()); | 614 ASSERT_EQ(expr->context(), expr->right()->context()); |
638 Visit(expr->left()); | 615 Visit(expr->left()); |
639 Visit(expr->right()); | 616 Visit(expr->right()); |
640 break; | 617 break; |
641 | 618 |
642 case Token::OR: | 619 case Token::OR: |
643 case Token::AND: | 620 case Token::AND: |
644 EmitLogicalOperation(expr); | 621 EmitLogicalOperation(expr); |
645 break; | 622 break; |
646 | 623 |
647 case Token::ADD: | 624 case Token::ADD: |
648 case Token::SUB: | 625 case Token::SUB: |
649 case Token::DIV: | 626 case Token::DIV: |
650 case Token::MOD: | 627 case Token::MOD: |
651 case Token::MUL: | 628 case Token::MUL: |
652 case Token::BIT_OR: | 629 case Token::BIT_OR: |
653 case Token::BIT_AND: | 630 case Token::BIT_AND: |
654 case Token::BIT_XOR: | 631 case Token::BIT_XOR: |
655 case Token::SHL: | 632 case Token::SHL: |
656 case Token::SHR: | 633 case Token::SHR: |
657 case Token::SAR: { | 634 case Token::SAR: { |
658 ASSERT(expr->left()->location().is_value()); | 635 ASSERT_EQ(Expression::kValue, expr->left()->context()); |
659 ASSERT(expr->right()->location().is_value()); | 636 ASSERT_EQ(Expression::kValue, expr->right()->context()); |
660 | 637 |
661 Visit(expr->left()); | 638 Visit(expr->left()); |
662 Visit(expr->right()); | 639 Visit(expr->right()); |
663 GenericBinaryOpStub stub(expr->op(), | 640 GenericBinaryOpStub stub(expr->op(), |
664 NO_OVERWRITE, | 641 NO_OVERWRITE, |
665 NO_GENERIC_BINARY_FLAGS); | 642 NO_GENERIC_BINARY_FLAGS); |
666 __ CallStub(&stub); | 643 __ CallStub(&stub); |
667 Move(expr->location(), eax); | 644 Move(expr->context(), eax); |
668 | 645 |
669 break; | 646 break; |
670 } | 647 } |
671 default: | 648 default: |
672 UNREACHABLE(); | 649 UNREACHABLE(); |
673 } | 650 } |
674 } | 651 } |
675 | 652 |
676 | 653 |
677 void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { | 654 void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { |
678 // Compile a short-circuited boolean operation in a non-test context. | 655 // Compile a short-circuited boolean operation in a non-test context. |
679 | 656 |
680 // Compile (e0 || e1) or (e0 && e1) as if it were | 657 // Compile (e0 || e1) or (e0 && e1) as if it were |
681 // (let (temp = e0) temp [or !temp, for &&] ? temp : e1). | 658 // (let (temp = e0) temp [or !temp, for &&] ? temp : e1). |
682 | 659 |
683 Label eval_right, done; | 660 Label eval_right, done; |
684 Label *left_true, *left_false; // Where to branch to if lhs has that value. | 661 Label *left_true, *left_false; // Where to branch to if lhs has that value. |
685 if (expr->op() == Token::OR) { | 662 if (expr->op() == Token::OR) { |
686 left_true = &done; | 663 left_true = &done; |
687 left_false = &eval_right; | 664 left_false = &eval_right; |
688 } else { | 665 } else { |
689 left_true = &eval_right; | 666 left_true = &eval_right; |
690 left_false = &done; | 667 left_false = &done; |
691 } | 668 } |
692 Location destination = expr->location(); | 669 Expression::Context context = expr->context(); |
693 Expression* left = expr->left(); | 670 Expression* left = expr->left(); |
694 Expression* right = expr->right(); | 671 Expression* right = expr->right(); |
695 | 672 |
696 // Use the shared ToBoolean stub to find the boolean value of the | 673 // Use the shared ToBoolean stub to find the boolean value of the |
697 // left-hand subexpression. Load the value into eax to perform some | 674 // left-hand subexpression. Load the value into eax to perform some |
698 // inlined checks assumed by the stub. | 675 // inlined checks assumed by the stub. |
699 | 676 |
700 // Compile the left-hand value into eax. Put it on the stack if we may | 677 // Compile the left-hand value into eax. Put it on the stack if we may |
701 // need it as the value of the whole expression. | 678 // need it as the value of the whole expression. |
702 if (left->AsLiteral() != NULL) { | 679 if (left->AsLiteral() != NULL) { |
703 __ mov(eax, left->AsLiteral()->handle()); | 680 __ mov(eax, left->AsLiteral()->handle()); |
704 if (destination.is_value()) __ push(eax); | 681 if (context == Expression::kValue) __ push(eax); |
705 } else { | 682 } else { |
706 Visit(left); | 683 Visit(left); |
707 ASSERT(left->location().is_value()); | 684 ASSERT_EQ(Expression::kValue, left->context()); |
708 switch (destination.type()) { | 685 switch (context) { |
709 case Location::kUninitialized: | 686 case Expression::kUninitialized: |
710 UNREACHABLE(); | 687 UNREACHABLE(); |
711 case Location::kEffect: | 688 case Expression::kEffect: |
712 // Pop the left-hand value into eax because we will not need it as the | 689 // Pop the left-hand value into eax because we will not need it as the |
713 // final result. | 690 // final result. |
714 __ pop(eax); | 691 __ pop(eax); |
715 break; | 692 break; |
716 case Location::kValue: | 693 case Expression::kValue: |
717 // Copy the left-hand value into eax because we may need it as the | 694 // Copy the left-hand value into eax because we may need it as the |
718 // final result. | 695 // final result. |
719 __ mov(eax, Operand(esp, 0)); | 696 __ mov(eax, Operand(esp, 0)); |
720 break; | 697 break; |
721 } | 698 } |
722 } | 699 } |
723 // The left-hand value is in eax. It is also on the stack iff the | 700 // The left-hand value is in eax. It is also on the stack iff the |
724 // destination location is value. | 701 // destination location is value. |
725 | 702 |
726 // Perform fast checks assumed by the stub. | 703 // Perform fast checks assumed by the stub. |
727 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. | 704 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. |
728 __ j(equal, left_false); | 705 __ j(equal, left_false); |
729 __ cmp(eax, Factory::true_value()); // True is true. | 706 __ cmp(eax, Factory::true_value()); // True is true. |
730 __ j(equal, left_true); | 707 __ j(equal, left_true); |
731 __ cmp(eax, Factory::false_value()); // False is false. | 708 __ cmp(eax, Factory::false_value()); // False is false. |
732 __ j(equal, left_false); | 709 __ j(equal, left_false); |
733 ASSERT(kSmiTag == 0); | 710 ASSERT_EQ(0, kSmiTag); |
734 __ test(eax, Operand(eax)); // The smi zero is false. | 711 __ test(eax, Operand(eax)); // The smi zero is false. |
735 __ j(zero, left_false); | 712 __ j(zero, left_false); |
736 __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. | 713 __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. |
737 __ j(zero, left_true); | 714 __ j(zero, left_true); |
738 | 715 |
739 // Call the stub for all other cases. | 716 // Call the stub for all other cases. |
740 __ push(eax); | 717 __ push(eax); |
741 ToBooleanStub stub; | 718 ToBooleanStub stub; |
742 __ CallStub(&stub); | 719 __ CallStub(&stub); |
743 __ test(eax, Operand(eax)); // The stub returns nonzero for true. | 720 __ test(eax, Operand(eax)); // The stub returns nonzero for true. |
744 if (expr->op() == Token::OR) { | 721 if (expr->op() == Token::OR) { |
745 __ j(not_zero, &done); | 722 __ j(not_zero, &done); |
746 } else { | 723 } else { |
747 __ j(zero, &done); | 724 __ j(zero, &done); |
748 } | 725 } |
749 | 726 |
750 __ bind(&eval_right); | 727 __ bind(&eval_right); |
751 // Discard the left-hand value if present on the stack. | 728 // Discard the left-hand value if present on the stack. |
752 if (destination.is_value()) { | 729 if (context == Expression::kValue) { |
753 __ add(Operand(esp), Immediate(kPointerSize)); | 730 __ add(Operand(esp), Immediate(kPointerSize)); |
754 } | 731 } |
755 // Save or discard the right-hand value as needed. | 732 // Save or discard the right-hand value as needed. |
756 Visit(right); | 733 Visit(right); |
757 ASSERT_EQ(destination.type(), right->location().type()); | 734 ASSERT_EQ(context, right->context()); |
758 | 735 |
759 __ bind(&done); | 736 __ bind(&done); |
760 } | 737 } |
761 | 738 |
762 | 739 |
763 } } // namespace v8::internal | 740 } } // namespace v8::internal |
OLD | NEW |