OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 __ mov(eax, CodeGenerator::GlobalObject()); | 940 __ mov(eax, CodeGenerator::GlobalObject()); |
941 __ mov(ecx, slot->var()->name()); | 941 __ mov(ecx, slot->var()->name()); |
942 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 942 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
943 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 943 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
944 ? RelocInfo::CODE_TARGET | 944 ? RelocInfo::CODE_TARGET |
945 : RelocInfo::CODE_TARGET_CONTEXT; | 945 : RelocInfo::CODE_TARGET_CONTEXT; |
946 __ call(ic, mode); | 946 __ call(ic, mode); |
947 } | 947 } |
948 | 948 |
949 | 949 |
| 950 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( |
| 951 Slot* slot, |
| 952 Label* slow) { |
| 953 ASSERT(slot->type() == Slot::CONTEXT); |
| 954 Register context = esi; |
| 955 Register temp = ebx; |
| 956 |
| 957 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 958 if (s->num_heap_slots() > 0) { |
| 959 if (s->calls_eval()) { |
| 960 // Check that extension is NULL. |
| 961 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
| 962 Immediate(0)); |
| 963 __ j(not_equal, slow); |
| 964 } |
| 965 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 966 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 967 // Walk the rest of the chain using a single register without |
| 968 // clobbering esi. |
| 969 context = temp; |
| 970 } |
| 971 } |
| 972 // Check that last extension is NULL. |
| 973 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
| 974 __ j(not_equal, slow); |
| 975 __ mov(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 976 return ContextOperand(temp, slot->index()); |
| 977 } |
| 978 |
| 979 |
| 980 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( |
| 981 Slot* slot, |
| 982 TypeofState typeof_state, |
| 983 Label* slow, |
| 984 Label* done) { |
| 985 // Generate fast-case code for variables that might be shadowed by |
| 986 // eval-introduced variables. Eval is used a lot without |
| 987 // introducing variables. In those cases, we do not want to |
| 988 // perform a runtime call for all variables in the scope |
| 989 // containing the eval. |
| 990 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 991 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 992 __ jmp(done); |
| 993 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 994 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 995 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); |
| 996 if (potential_slot != NULL) { |
| 997 // Generate fast case for locals that rewrite to slots. |
| 998 __ mov(eax, |
| 999 ContextSlotOperandCheckExtensions(potential_slot, slow)); |
| 1000 if (potential_slot->var()->mode() == Variable::CONST) { |
| 1001 __ cmp(eax, Factory::the_hole_value()); |
| 1002 __ j(not_equal, done); |
| 1003 __ mov(eax, Factory::undefined_value()); |
| 1004 } |
| 1005 __ jmp(done); |
| 1006 } else if (rewrite != NULL) { |
| 1007 // Generate fast case for calls of an argument function. |
| 1008 Property* property = rewrite->AsProperty(); |
| 1009 if (property != NULL) { |
| 1010 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1011 Literal* key_literal = property->key()->AsLiteral(); |
| 1012 if (obj_proxy != NULL && |
| 1013 key_literal != NULL && |
| 1014 obj_proxy->IsArguments() && |
| 1015 key_literal->handle()->IsSmi()) { |
| 1016 // Load arguments object if there are no eval-introduced |
| 1017 // variables. Then load the argument from the arguments |
| 1018 // object using keyed load. |
| 1019 __ mov(edx, |
| 1020 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
| 1021 slow)); |
| 1022 __ mov(eax, Immediate(key_literal->handle())); |
| 1023 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1024 __ call(ic, RelocInfo::CODE_TARGET); |
| 1025 __ jmp(done); |
| 1026 } |
| 1027 } |
| 1028 } |
| 1029 } |
| 1030 } |
| 1031 |
| 1032 |
950 void FullCodeGenerator::EmitVariableLoad(Variable* var, | 1033 void FullCodeGenerator::EmitVariableLoad(Variable* var, |
951 Expression::Context context) { | 1034 Expression::Context context) { |
952 // Four cases: non-this global variables, lookup slots, all other | 1035 // Four cases: non-this global variables, lookup slots, all other |
953 // types of slots, and parameters that rewrite to explicit property | 1036 // types of slots, and parameters that rewrite to explicit property |
954 // accesses on the arguments object. | 1037 // accesses on the arguments object. |
955 Slot* slot = var->slot(); | 1038 Slot* slot = var->slot(); |
956 Property* property = var->AsProperty(); | 1039 Property* property = var->AsProperty(); |
957 | 1040 |
958 if (var->is_global() && !var->is_this()) { | 1041 if (var->is_global() && !var->is_this()) { |
959 Comment cmnt(masm_, "Global variable"); | 1042 Comment cmnt(masm_, "Global variable"); |
960 // Use inline caching. Variable name is passed in ecx and the global | 1043 // Use inline caching. Variable name is passed in ecx and the global |
961 // object on the stack. | 1044 // object on the stack. |
962 __ mov(eax, CodeGenerator::GlobalObject()); | 1045 __ mov(eax, CodeGenerator::GlobalObject()); |
963 __ mov(ecx, var->name()); | 1046 __ mov(ecx, var->name()); |
964 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1047 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
965 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1048 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
966 // By emitting a nop we make sure that we do not have a test eax | 1049 // By emitting a nop we make sure that we do not have a test eax |
967 // instruction after the call it is treated specially by the LoadIC code | 1050 // instruction after the call it is treated specially by the LoadIC code |
968 // Remember that the assembler may choose to do peephole optimization | 1051 // Remember that the assembler may choose to do peephole optimization |
969 // (eg, push/pop elimination). | 1052 // (eg, push/pop elimination). |
970 __ nop(); | 1053 __ nop(); |
971 Apply(context, eax); | 1054 Apply(context, eax); |
972 | 1055 |
973 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1056 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
974 Label done, slow; | 1057 Label done, slow; |
975 | 1058 |
976 // Generate fast-case code for variables that might be shadowed by | 1059 // Generate code for loading from variables potentially shadowed |
977 // eval-introduced variables. Eval is used a lot without | 1060 // by eval-introduced variables. |
978 // introducing variables. In those cases, we do not want to | 1061 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
979 // perform a runtime call for all variables in the scope | |
980 // containing the eval. | |
981 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | |
982 EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow); | |
983 Apply(context, eax); | |
984 __ jmp(&done); | |
985 } | |
986 | 1062 |
987 __ bind(&slow); | 1063 __ bind(&slow); |
988 Comment cmnt(masm_, "Lookup slot"); | 1064 Comment cmnt(masm_, "Lookup slot"); |
989 __ push(esi); // Context. | 1065 __ push(esi); // Context. |
990 __ push(Immediate(var->name())); | 1066 __ push(Immediate(var->name())); |
991 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1067 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1068 __ bind(&done); |
| 1069 |
992 Apply(context, eax); | 1070 Apply(context, eax); |
993 __ bind(&done); | |
994 | 1071 |
995 } else if (slot != NULL) { | 1072 } else if (slot != NULL) { |
996 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1073 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
997 ? "Context slot" | 1074 ? "Context slot" |
998 : "Stack slot"); | 1075 : "Stack slot"); |
999 if (var->mode() == Variable::CONST) { | 1076 if (var->mode() == Variable::CONST) { |
1000 // Constants may be the hole value if they have not been initialized. | 1077 // Constants may be the hole value if they have not been initialized. |
1001 // Unhole them. | 1078 // Unhole them. |
1002 Label done; | 1079 Label done; |
1003 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1080 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
(...skipping 1019 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2023 __ CallStub(&stub); | 2100 __ CallStub(&stub); |
2024 // Restore context register. | 2101 // Restore context register. |
2025 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2102 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
2026 DropAndApply(1, context_, eax); | 2103 DropAndApply(1, context_, eax); |
2027 } else if (var != NULL && !var->is_this() && var->is_global()) { | 2104 } else if (var != NULL && !var->is_this() && var->is_global()) { |
2028 // Push global object as receiver for the call IC. | 2105 // Push global object as receiver for the call IC. |
2029 __ push(CodeGenerator::GlobalObject()); | 2106 __ push(CodeGenerator::GlobalObject()); |
2030 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); | 2107 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); |
2031 } else if (var != NULL && var->slot() != NULL && | 2108 } else if (var != NULL && var->slot() != NULL && |
2032 var->slot()->type() == Slot::LOOKUP) { | 2109 var->slot()->type() == Slot::LOOKUP) { |
2033 // Call to a lookup slot (dynamically introduced variable). Call the | 2110 // Call to a lookup slot (dynamically introduced variable). |
2034 // runtime to find the function to call (returned in eax) and the object | 2111 Label slow, done; |
2035 // holding it (returned in edx). | 2112 |
| 2113 // Generate code for loading from variables potentially shadowed |
| 2114 // by eval-introduced variables. |
| 2115 EmitDynamicLoadFromSlotFastCase(var->slot(), |
| 2116 NOT_INSIDE_TYPEOF, |
| 2117 &slow, |
| 2118 &done); |
| 2119 |
| 2120 __ bind(&slow); |
| 2121 // Call the runtime to find the function to call (returned in eax) |
| 2122 // and the object holding it (returned in edx). |
2036 __ push(context_register()); | 2123 __ push(context_register()); |
2037 __ push(Immediate(var->name())); | 2124 __ push(Immediate(var->name())); |
2038 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2125 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
2039 __ push(eax); // Function. | 2126 __ push(eax); // Function. |
2040 __ push(edx); // Receiver. | 2127 __ push(edx); // Receiver. |
| 2128 |
| 2129 // If fast case code has been generated, emit code to push the |
| 2130 // function and receiver and have the slow path jump around this |
| 2131 // code. |
| 2132 if (done.is_linked()) { |
| 2133 Label call; |
| 2134 __ jmp(&call); |
| 2135 __ bind(&done); |
| 2136 // Push function. |
| 2137 __ push(eax); |
| 2138 // Push global receiver. |
| 2139 __ mov(ebx, CodeGenerator::GlobalObject()); |
| 2140 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
| 2141 __ bind(&call); |
| 2142 } |
| 2143 |
2041 EmitCallWithStub(expr); | 2144 EmitCallWithStub(expr); |
2042 } else if (fun->AsProperty() != NULL) { | 2145 } else if (fun->AsProperty() != NULL) { |
2043 // Call to an object property. | 2146 // Call to an object property. |
2044 Property* prop = fun->AsProperty(); | 2147 Property* prop = fun->AsProperty(); |
2045 Literal* key = prop->key()->AsLiteral(); | 2148 Literal* key = prop->key()->AsLiteral(); |
2046 if (key != NULL && key->handle()->IsSymbol()) { | 2149 if (key != NULL && key->handle()->IsSymbol()) { |
2047 // Call to a named property, use call IC. | 2150 // Call to a named property, use call IC. |
2048 VisitForValue(prop->obj(), kStack); | 2151 VisitForValue(prop->obj(), kStack); |
2049 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2152 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
2050 } else { | 2153 } else { |
(...skipping 1283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3334 __ mov(eax, CodeGenerator::GlobalObject()); | 3437 __ mov(eax, CodeGenerator::GlobalObject()); |
3335 __ mov(ecx, Immediate(proxy->name())); | 3438 __ mov(ecx, Immediate(proxy->name())); |
3336 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3439 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
3337 // Use a regular load, not a contextual load, to avoid a reference | 3440 // Use a regular load, not a contextual load, to avoid a reference |
3338 // error. | 3441 // error. |
3339 __ call(ic, RelocInfo::CODE_TARGET); | 3442 __ call(ic, RelocInfo::CODE_TARGET); |
3340 if (where == kStack) __ push(eax); | 3443 if (where == kStack) __ push(eax); |
3341 } else if (proxy != NULL && | 3444 } else if (proxy != NULL && |
3342 proxy->var()->slot() != NULL && | 3445 proxy->var()->slot() != NULL && |
3343 proxy->var()->slot()->type() == Slot::LOOKUP) { | 3446 proxy->var()->slot()->type() == Slot::LOOKUP) { |
| 3447 Label done, slow; |
| 3448 |
| 3449 // Generate code for loading from variables potentially shadowed |
| 3450 // by eval-introduced variables. |
| 3451 Slot* slot = proxy->var()->slot(); |
| 3452 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 3453 |
| 3454 __ bind(&slow); |
3344 __ push(esi); | 3455 __ push(esi); |
3345 __ push(Immediate(proxy->name())); | 3456 __ push(Immediate(proxy->name())); |
3346 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3457 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3458 __ bind(&done); |
| 3459 |
3347 if (where == kStack) __ push(eax); | 3460 if (where == kStack) __ push(eax); |
3348 } else { | 3461 } else { |
3349 // This expression cannot throw a reference error at the top level. | 3462 // This expression cannot throw a reference error at the top level. |
3350 VisitForValue(expr, where); | 3463 VisitForValue(expr, where); |
3351 } | 3464 } |
3352 } | 3465 } |
3353 | 3466 |
3354 | 3467 |
3355 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 3468 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, |
3356 Expression* left, | 3469 Expression* left, |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3620 // And return. | 3733 // And return. |
3621 __ ret(0); | 3734 __ ret(0); |
3622 } | 3735 } |
3623 | 3736 |
3624 | 3737 |
3625 #undef __ | 3738 #undef __ |
3626 | 3739 |
3627 } } // namespace v8::internal | 3740 } } // namespace v8::internal |
3628 | 3741 |
3629 #endif // V8_TARGET_ARCH_IA32 | 3742 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |