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 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 __ movq(rax, Operand(rsp, 0)); | 263 __ movq(rax, Operand(rsp, 0)); |
264 TestAndBranch(rax, &discard, false_label_); | 264 TestAndBranch(rax, &discard, false_label_); |
265 __ bind(&discard); | 265 __ bind(&discard); |
266 __ Drop(1); | 266 __ Drop(1); |
267 __ jmp(true_label_); | 267 __ jmp(true_label_); |
268 } | 268 } |
269 } | 269 } |
270 } | 270 } |
271 | 271 |
272 | 272 |
273 template <> | 273 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
274 Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source, | 274 switch (slot->type()) { |
275 Register scratch) { | |
276 switch (source->type()) { | |
277 case Slot::PARAMETER: | 275 case Slot::PARAMETER: |
278 case Slot::LOCAL: | 276 case Slot::LOCAL: |
279 return Operand(rbp, SlotOffset(source)); | 277 return Operand(rbp, SlotOffset(slot)); |
280 case Slot::CONTEXT: { | 278 case Slot::CONTEXT: { |
281 int context_chain_length = | 279 int context_chain_length = |
282 function_->scope()->ContextChainLength(source->var()->scope()); | 280 function_->scope()->ContextChainLength(slot->var()->scope()); |
283 __ LoadContext(scratch, context_chain_length); | 281 __ LoadContext(scratch, context_chain_length); |
284 return CodeGenerator::ContextOperand(scratch, source->index()); | 282 return CodeGenerator::ContextOperand(scratch, slot->index()); |
285 } | 283 } |
286 case Slot::LOOKUP: | 284 case Slot::LOOKUP: |
287 UNIMPLEMENTED(); | 285 UNREACHABLE(); |
288 } | 286 } |
289 UNREACHABLE(); | 287 UNREACHABLE(); |
290 return Operand(rax, 0); | 288 return Operand(rax, 0); |
291 } | 289 } |
292 | 290 |
293 | 291 |
294 void FastCodeGenerator::Move(Register dst, Slot* source) { | 292 void FastCodeGenerator::Move(Register destination, Slot* source) { |
295 Operand location = CreateSlotOperand<Operand>(source, dst); | 293 MemOperand location = EmitSlotSearch(source, destination); |
296 __ movq(dst, location); | 294 __ movq(destination, location); |
297 } | 295 } |
298 | 296 |
299 | 297 |
300 void FastCodeGenerator::Move(Expression::Context context, | 298 void FastCodeGenerator::Move(Expression::Context context, |
301 Slot* source, | 299 Slot* source, |
302 Register scratch) { | 300 Register scratch) { |
303 switch (context) { | 301 switch (context) { |
304 case Expression::kUninitialized: | 302 case Expression::kUninitialized: |
305 UNREACHABLE(); | 303 UNREACHABLE(); |
306 case Expression::kEffect: | 304 case Expression::kEffect: |
307 break; | 305 break; |
308 case Expression::kValue: { | 306 case Expression::kValue: { |
309 Operand location = CreateSlotOperand<Operand>(source, scratch); | 307 MemOperand location = EmitSlotSearch(source, scratch); |
310 __ push(location); | 308 __ push(location); |
311 break; | 309 break; |
312 } | 310 } |
313 case Expression::kTest: | 311 case Expression::kTest: |
314 case Expression::kValueTest: | 312 case Expression::kValueTest: |
315 case Expression::kTestValue: | 313 case Expression::kTestValue: |
316 Move(scratch, source); | 314 Move(scratch, source); |
317 Move(context, scratch); | 315 Move(context, scratch); |
318 break; | 316 break; |
319 } | 317 } |
(...skipping 16 matching lines...) Expand all Loading... |
336 Move(context, rax); | 334 Move(context, rax); |
337 break; | 335 break; |
338 } | 336 } |
339 } | 337 } |
340 | 338 |
341 | 339 |
342 void FastCodeGenerator::Move(Slot* dst, | 340 void FastCodeGenerator::Move(Slot* dst, |
343 Register src, | 341 Register src, |
344 Register scratch1, | 342 Register scratch1, |
345 Register scratch2) { | 343 Register scratch2) { |
346 switch (dst->type()) { | 344 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. |
347 case Slot::PARAMETER: | 345 ASSERT(!scratch1.is(src) && !scratch2.is(src)); |
348 case Slot::LOCAL: | 346 MemOperand location = EmitSlotSearch(dst, scratch1); |
349 __ movq(Operand(rbp, SlotOffset(dst)), src); | 347 __ movq(location, src); |
350 break; | 348 // Emit the write barrier code if the location is in the heap. |
351 case Slot::CONTEXT: { | 349 if (dst->type() == Slot::CONTEXT) { |
352 ASSERT(!src.is(scratch1)); | 350 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
353 ASSERT(!src.is(scratch2)); | 351 __ RecordWrite(scratch1, offset, src, scratch2); |
354 ASSERT(!scratch1.is(scratch2)); | |
355 int context_chain_length = | |
356 function_->scope()->ContextChainLength(dst->var()->scope()); | |
357 __ LoadContext(scratch1, context_chain_length); | |
358 __ movq(Operand(scratch1, Context::SlotOffset(dst->index())), src); | |
359 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | |
360 __ RecordWrite(scratch1, offset, src, scratch2); | |
361 break; | |
362 } | |
363 case Slot::LOOKUP: | |
364 UNIMPLEMENTED(); | |
365 } | 352 } |
366 } | 353 } |
367 | 354 |
368 | 355 |
369 void FastCodeGenerator::DropAndMove(Expression::Context context, | 356 void FastCodeGenerator::DropAndMove(Expression::Context context, |
370 Register source, | 357 Register source, |
371 int drop_count) { | 358 int drop_count) { |
372 ASSERT(drop_count > 0); | 359 ASSERT(drop_count > 0); |
373 switch (context) { | 360 switch (context) { |
374 case Expression::kUninitialized: | 361 case Expression::kUninitialized: |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 ASSERT(var != NULL); // Must have been resolved. | 437 ASSERT(var != NULL); // Must have been resolved. |
451 Slot* slot = var->slot(); | 438 Slot* slot = var->slot(); |
452 Property* prop = var->AsProperty(); | 439 Property* prop = var->AsProperty(); |
453 | 440 |
454 if (slot != NULL) { | 441 if (slot != NULL) { |
455 switch (slot->type()) { | 442 switch (slot->type()) { |
456 case Slot::PARAMETER: | 443 case Slot::PARAMETER: |
457 case Slot::LOCAL: | 444 case Slot::LOCAL: |
458 if (decl->mode() == Variable::CONST) { | 445 if (decl->mode() == Variable::CONST) { |
459 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 446 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
460 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 447 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); |
461 } else if (decl->fun() != NULL) { | 448 } else if (decl->fun() != NULL) { |
462 Visit(decl->fun()); | 449 Visit(decl->fun()); |
463 __ pop(Operand(rbp, SlotOffset(var->slot()))); | 450 __ pop(Operand(rbp, SlotOffset(slot))); |
464 } | 451 } |
465 break; | 452 break; |
466 | 453 |
467 case Slot::CONTEXT: | 454 case Slot::CONTEXT: |
| 455 // We bypass the general EmitSlotSearch because we know more about |
| 456 // this specific context. |
| 457 |
468 // The variable in the decl always resides in the current context. | 458 // The variable in the decl always resides in the current context. |
469 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); | 459 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); |
470 if (FLAG_debug_code) { | 460 if (FLAG_debug_code) { |
471 // Check if we have the correct context pointer. | 461 // Check if we have the correct context pointer. |
472 __ movq(rbx, | 462 __ movq(rbx, |
473 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); | 463 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); |
474 __ cmpq(rbx, rsi); | 464 __ cmpq(rbx, rsi); |
475 __ Check(equal, "Unexpected declaration in current context."); | 465 __ Check(equal, "Unexpected declaration in current context."); |
476 } | 466 } |
477 if (decl->mode() == Variable::CONST) { | 467 if (decl->mode() == Variable::CONST) { |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
901 // assignment. Right-hand-side value is passed in rax, variable name in | 891 // assignment. Right-hand-side value is passed in rax, variable name in |
902 // rcx, and the global object on the stack. | 892 // rcx, and the global object on the stack. |
903 __ pop(rax); | 893 __ pop(rax); |
904 __ Move(rcx, var->name()); | 894 __ Move(rcx, var->name()); |
905 __ push(CodeGenerator::GlobalObject()); | 895 __ push(CodeGenerator::GlobalObject()); |
906 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 896 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
907 __ Call(ic, RelocInfo::CODE_TARGET); | 897 __ Call(ic, RelocInfo::CODE_TARGET); |
908 // Overwrite the global object on the stack with the result if needed. | 898 // Overwrite the global object on the stack with the result if needed. |
909 DropAndMove(context, rax); | 899 DropAndMove(context, rax); |
910 | 900 |
911 } else if (var->slot()) { | 901 } else if (var->slot() != NULL) { |
912 Slot* slot = var->slot(); | 902 Slot* slot = var->slot(); |
913 ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. | |
914 switch (slot->type()) { | 903 switch (slot->type()) { |
915 case Slot::LOCAL: | 904 case Slot::LOCAL: |
916 case Slot::PARAMETER: { | 905 case Slot::PARAMETER: { |
| 906 Operand target = Operand(rbp, SlotOffset(slot)); |
917 switch (context) { | 907 switch (context) { |
918 case Expression::kUninitialized: | 908 case Expression::kUninitialized: |
919 UNREACHABLE(); | 909 UNREACHABLE(); |
920 case Expression::kEffect: | 910 case Expression::kEffect: |
921 // Perform assignment and discard value. | 911 // Perform assignment and discard value. |
922 __ pop(Operand(rbp, SlotOffset(var->slot()))); | 912 __ pop(target); |
923 break; | 913 break; |
924 case Expression::kValue: | 914 case Expression::kValue: |
925 // Perform assignment and preserve value. | 915 // Perform assignment and preserve value. |
926 __ movq(rax, Operand(rsp, 0)); | 916 __ movq(rax, Operand(rsp, 0)); |
927 __ movq(Operand(rbp, SlotOffset(var->slot())), rax); | 917 __ movq(target, rax); |
928 break; | 918 break; |
929 case Expression::kTest: | 919 case Expression::kTest: |
930 // Perform assignment and test (and discard) value. | 920 // Perform assignment and test (and discard) value. |
931 __ pop(rax); | 921 __ pop(rax); |
932 __ movq(Operand(rbp, SlotOffset(var->slot())), rax); | 922 __ movq(target, rax); |
933 TestAndBranch(rax, true_label_, false_label_); | 923 TestAndBranch(rax, true_label_, false_label_); |
934 break; | 924 break; |
935 case Expression::kValueTest: { | 925 case Expression::kValueTest: { |
936 Label discard; | 926 Label discard; |
937 __ movq(rax, Operand(rsp, 0)); | 927 __ movq(rax, Operand(rsp, 0)); |
938 __ movq(Operand(rbp, SlotOffset(var->slot())), rax); | 928 __ movq(target, rax); |
939 TestAndBranch(rax, true_label_, &discard); | 929 TestAndBranch(rax, true_label_, &discard); |
940 __ bind(&discard); | 930 __ bind(&discard); |
941 __ addq(rsp, Immediate(kPointerSize)); | 931 __ addq(rsp, Immediate(kPointerSize)); |
942 __ jmp(false_label_); | 932 __ jmp(false_label_); |
943 break; | 933 break; |
944 } | 934 } |
945 case Expression::kTestValue: { | 935 case Expression::kTestValue: { |
946 Label discard; | 936 Label discard; |
947 __ movq(rax, Operand(rsp, 0)); | 937 __ movq(rax, Operand(rsp, 0)); |
948 __ movq(Operand(rbp, SlotOffset(var->slot())), rax); | 938 __ movq(target, rax); |
949 TestAndBranch(rax, &discard, false_label_); | 939 TestAndBranch(rax, &discard, false_label_); |
950 __ bind(&discard); | 940 __ bind(&discard); |
951 __ addq(rsp, Immediate(kPointerSize)); | 941 __ addq(rsp, Immediate(kPointerSize)); |
952 __ jmp(true_label_); | 942 __ jmp(true_label_); |
953 break; | 943 break; |
954 } | 944 } |
955 } | 945 } |
956 break; | 946 break; |
957 } | 947 } |
958 | 948 |
959 case Slot::CONTEXT: { | 949 case Slot::CONTEXT: { |
960 int chain_length = | 950 MemOperand target = EmitSlotSearch(slot, rcx); |
961 function_->scope()->ContextChainLength(slot->var()->scope()); | 951 __ pop(rax); |
962 if (chain_length > 0) { | 952 __ movq(target, rax); |
963 // Move up the context chain to the context containing the slot. | |
964 __ movq(rax, | |
965 Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX))); | |
966 // Load the function context (which is the incoming, outer context). | |
967 __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset)); | |
968 for (int i = 1; i < chain_length; i++) { | |
969 __ movq(rax, | |
970 Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX))); | |
971 __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset)); | |
972 } | |
973 } else { // Slot is in the current context. Generate optimized code. | |
974 __ movq(rax, rsi); // RecordWrite destroys the object register. | |
975 } | |
976 if (FLAG_debug_code) { | |
977 __ cmpq(rax, | |
978 Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX))); | |
979 __ Check(equal, "Context Slot chain length wrong."); | |
980 } | |
981 __ pop(rcx); | |
982 __ movq(Operand(rax, Context::SlotOffset(slot->index())), rcx); | |
983 | 953 |
984 // RecordWrite may destroy all its register arguments. | 954 // RecordWrite may destroy all its register arguments. |
985 if (context == Expression::kValue) { | 955 if (context == Expression::kValue) { |
986 __ push(rcx); | 956 __ push(rax); |
987 } else if (context != Expression::kEffect) { | 957 } else if (context != Expression::kEffect) { |
988 __ movq(rdx, rcx); | 958 __ movq(rdx, rax); |
989 } | 959 } |
990 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 960 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
991 __ RecordWrite(rax, offset, rcx, rbx); | 961 __ RecordWrite(rcx, offset, rax, rbx); |
992 if (context != Expression::kEffect && | 962 if (context != Expression::kEffect && |
993 context != Expression::kValue) { | 963 context != Expression::kValue) { |
994 Move(context, rdx); | 964 Move(context, rdx); |
995 } | 965 } |
996 break; | 966 break; |
997 } | 967 } |
998 | 968 |
999 case Slot::LOOKUP: | 969 case Slot::LOOKUP: |
1000 UNREACHABLE(); | 970 UNREACHABLE(); |
1001 break; | 971 break; |
1002 } | 972 } |
| 973 } else { |
| 974 // Variables rewritten as properties are not treated as variables in |
| 975 // assignments. |
| 976 UNREACHABLE(); |
1003 } | 977 } |
1004 } | 978 } |
1005 | 979 |
1006 | 980 |
1007 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 981 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
1008 // Assignment to a property, using a named store IC. | 982 // Assignment to a property, using a named store IC. |
1009 Property* prop = expr->target()->AsProperty(); | 983 Property* prop = expr->target()->AsProperty(); |
1010 ASSERT(prop != NULL); | 984 ASSERT(prop != NULL); |
1011 ASSERT(prop->key()->AsLiteral() != NULL); | 985 ASSERT(prop->key()->AsLiteral() != NULL); |
1012 | 986 |
(...skipping 797 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1810 __ movq(Operand(rsp, 0), rdx); | 1784 __ movq(Operand(rsp, 0), rdx); |
1811 // And return. | 1785 // And return. |
1812 __ ret(0); | 1786 __ ret(0); |
1813 } | 1787 } |
1814 | 1788 |
1815 | 1789 |
1816 #undef __ | 1790 #undef __ |
1817 | 1791 |
1818 | 1792 |
1819 } } // namespace v8::internal | 1793 } } // namespace v8::internal |
OLD | NEW |