Chromium Code Reviews| 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 |