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