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