Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/codegen-ia32.cc

Issue 20499: Experimental: merge from bleeding edge 1298:1307. Port the eval... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: '' Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/codegen-ia32.h ('k') | src/contexts.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 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 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 return frame_->ParameterAt(index); 337 return frame_->ParameterAt(index);
338 338
339 case Slot::LOCAL: 339 case Slot::LOCAL:
340 return frame_->LocalAt(index); 340 return frame_->LocalAt(index);
341 341
342 case Slot::CONTEXT: { 342 case Slot::CONTEXT: {
343 // Follow the context chain if necessary. 343 // Follow the context chain if necessary.
344 ASSERT(!tmp.is(esi)); // do not overwrite context register 344 ASSERT(!tmp.is(esi)); // do not overwrite context register
345 Register context = esi; 345 Register context = esi;
346 int chain_length = scope()->ContextChainLength(slot->var()->scope()); 346 int chain_length = scope()->ContextChainLength(slot->var()->scope());
347 for (int i = chain_length; i-- > 0;) { 347 for (int i = 0; i < chain_length; i++) {
348 // Load the closure. 348 // Load the closure.
349 // (All contexts, even 'with' contexts, have a closure, 349 // (All contexts, even 'with' contexts, have a closure,
350 // and it is the same for all contexts inside a function. 350 // and it is the same for all contexts inside a function.
351 // There is no need to go to the function context first.) 351 // There is no need to go to the function context first.)
352 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); 352 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
353 // Load the function context (which is the incoming, outer context). 353 // Load the function context (which is the incoming, outer context).
354 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); 354 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
355 context = tmp; 355 context = tmp;
356 } 356 }
357 // We may have a 'with' context now. Get the function context. 357 // We may have a 'with' context now. Get the function context.
358 // (In fact this mov may never be the needed, since the scope analysis 358 // (In fact this mov may never be the needed, since the scope analysis
359 // may not permit a direct context access in this case and thus we are 359 // may not permit a direct context access in this case and thus we are
360 // always at a function context. However it is safe to dereference be- 360 // always at a function context. However it is safe to dereference be-
361 // cause the function context of a function context is itself. Before 361 // cause the function context of a function context is itself. Before
362 // deleting this mov we should try to create a counter-example first, 362 // deleting this mov we should try to create a counter-example first,
363 // though...) 363 // though...)
364 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); 364 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
365 return ContextOperand(tmp, index); 365 return ContextOperand(tmp, index);
366 } 366 }
367 367
368 default: 368 default:
369 UNREACHABLE(); 369 UNREACHABLE();
370 return Operand(eax); 370 return Operand(eax);
371 } 371 }
372 } 372 }
373 373
374 374
375 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot,
376 Result tmp,
377 JumpTarget* slow) {
378 ASSERT(slot->type() == Slot::CONTEXT);
379 ASSERT(tmp.is_register());
380 Result context(esi, this);
381
382 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
383 if (s->num_heap_slots() > 0) {
384 if (s->calls_eval()) {
385 // Check that extension is NULL.
386 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX),
387 Immediate(0));
388 slow->Branch(not_equal, not_taken);
389 }
390 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX));
391 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset));
392 context = tmp;
393 }
394 }
395 // Check that last extension is NULL.
396 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX),
397 Immediate(0));
398 slow->Branch(not_equal, not_taken);
399 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::FCONTEXT_INDEX));
400 return ContextOperand(tmp.reg(), slot->index());
401 }
402
403
375 // Emit code to load the value of an expression to the top of the 404 // Emit code to load the value of an expression to the top of the
376 // frame. If the expression is boolean-valued it may be compiled (or 405 // frame. If the expression is boolean-valued it may be compiled (or
377 // partially compiled) into control flow to the control destination. 406 // partially compiled) into control flow to the control destination.
378 // If force_control is true, control flow is forced. 407 // If force_control is true, control flow is forced.
379 void CodeGenerator::LoadCondition(Expression* x, 408 void CodeGenerator::LoadCondition(Expression* x,
380 TypeofState typeof_state, 409 TypeofState typeof_state,
381 ControlDestination* dest, 410 ControlDestination* dest,
382 bool force_control) { 411 bool force_control) {
383 ASSERT(!in_spilled_code()); 412 ASSERT(!in_spilled_code());
384 #ifdef DEBUG 413 #ifdef DEBUG
(...skipping 1164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1549 Variable* var = node->proxy()->var(); 1578 Variable* var = node->proxy()->var();
1550 ASSERT(var != NULL); // must have been resolved 1579 ASSERT(var != NULL); // must have been resolved
1551 Slot* slot = var->slot(); 1580 Slot* slot = var->slot();
1552 1581
1553 // If it was not possible to allocate the variable at compile time, 1582 // If it was not possible to allocate the variable at compile time,
1554 // we need to "declare" it at runtime to make sure it actually 1583 // we need to "declare" it at runtime to make sure it actually
1555 // exists in the local context. 1584 // exists in the local context.
1556 if (slot != NULL && slot->type() == Slot::LOOKUP) { 1585 if (slot != NULL && slot->type() == Slot::LOOKUP) {
1557 // Variables with a "LOOKUP" slot were introduced as non-locals 1586 // Variables with a "LOOKUP" slot were introduced as non-locals
1558 // during variable resolution and must have mode DYNAMIC. 1587 // during variable resolution and must have mode DYNAMIC.
1559 ASSERT(var->mode() == Variable::DYNAMIC); 1588 ASSERT(var->is_dynamic());
1560 // For now, just do a runtime call. Duplicate the context register. 1589 // For now, just do a runtime call. Duplicate the context register.
1561 Result context(esi, this); 1590 Result context(esi, this);
1562 frame_->Push(&context); 1591 frame_->Push(&context);
1563 frame_->Push(var->name()); 1592 frame_->Push(var->name());
1564 // Declaration nodes are always introduced in one of two modes. 1593 // Declaration nodes are always introduced in one of two modes.
1565 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); 1594 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
1566 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; 1595 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
1567 frame_->Push(Smi::FromInt(attr)); 1596 frame_->Push(Smi::FromInt(attr));
1568 // Push initial value, if any. 1597 // Push initial value, if any.
1569 // Note: For variables we must not push an initial value (such as 1598 // Note: For variables we must not push an initial value (such as
(...skipping 1322 matching lines...) Expand 10 before | Expand all | Expand 10 after
2892 Load(node->else_expression(), typeof_state()); 2921 Load(node->else_expression(), typeof_state());
2893 } 2922 }
2894 } 2923 }
2895 2924
2896 exit.Bind(); 2925 exit.Bind();
2897 } 2926 }
2898 2927
2899 2928
2900 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { 2929 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
2901 if (slot->type() == Slot::LOOKUP) { 2930 if (slot->type() == Slot::LOOKUP) {
2902 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 2931 ASSERT(slot->var()->is_dynamic());
2903 2932
2904 // For now, just do a runtime call. 2933 JumpTarget slow(this);
2934 JumpTarget done(this);
2935 Result value(this);
2936
2937 // Generate fast-case code for variables that might be shadowed by
2938 // eval-introduced variables. Eval is used a lot without
2939 // introducing variables. In those cases, we do not want to
2940 // perform a runtime call for all variables in the scope
2941 // containing the eval.
2942 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
2943 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
2944 // If there was no control flow to slow, we can exit early.
2945 if (!slow.is_linked()) {
2946 frame_->Push(&value);
2947 return;
2948 }
2949
2950 done.Jump(&value);
2951
2952 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
2953 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
2954 // Allocate a fresh register to use as a temp in
2955 // ContextSlotOperandCheckExtensions and to hold the result
2956 // value.
2957 value = allocator_->Allocate();
2958 ASSERT(value.is_valid());
2959 __ mov(value.reg(),
2960 ContextSlotOperandCheckExtensions(potential_slot, value, &slow));
2961 // There is always control flow to slow from
2962 // ContextSlotOperandCheckExtensions.
2963 done.Jump(&value);
2964 }
2965
2966 slow.Bind();
2905 frame_->Push(esi); 2967 frame_->Push(esi);
2906 frame_->Push(slot->var()->name()); 2968 frame_->Push(slot->var()->name());
2907
2908 Result value(this);
2909 if (typeof_state == INSIDE_TYPEOF) { 2969 if (typeof_state == INSIDE_TYPEOF) {
2910 value = 2970 value =
2911 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 2971 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
2912 } else { 2972 } else {
2913 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); 2973 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
2914 } 2974 }
2975
2976 done.Bind(&value);
2915 frame_->Push(&value); 2977 frame_->Push(&value);
2916 2978
2917 } else if (slot->var()->mode() == Variable::CONST) { 2979 } else if (slot->var()->mode() == Variable::CONST) {
2918 // Const slots may contain 'the hole' value (the constant hasn't been 2980 // Const slots may contain 'the hole' value (the constant hasn't been
2919 // initialized yet) which needs to be converted into the 'undefined' 2981 // initialized yet) which needs to be converted into the 'undefined'
2920 // value. 2982 // value.
2921 // 2983 //
2922 // We currently spill the virtual frame because constants use the 2984 // We currently spill the virtual frame because constants use the
2923 // potentially unsafe direct-frame access of SlotOperand. 2985 // potentially unsafe direct-frame access of SlotOperand.
2924 VirtualFrame::SpilledScope spilled_scope(this); 2986 VirtualFrame::SpilledScope spilled_scope(this);
(...skipping 20 matching lines...) Expand all
2945 // because it will always be a context slot. 3007 // because it will always be a context slot.
2946 ASSERT(slot->type() == Slot::CONTEXT); 3008 ASSERT(slot->type() == Slot::CONTEXT);
2947 Result temp = allocator_->Allocate(); 3009 Result temp = allocator_->Allocate();
2948 ASSERT(temp.is_valid()); 3010 ASSERT(temp.is_valid());
2949 __ mov(temp.reg(), SlotOperand(slot, temp.reg())); 3011 __ mov(temp.reg(), SlotOperand(slot, temp.reg()));
2950 frame_->Push(&temp); 3012 frame_->Push(&temp);
2951 } 3013 }
2952 } 3014 }
2953 3015
2954 3016
3017 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
3018 Slot* slot,
3019 TypeofState typeof_state,
3020 JumpTarget* slow) {
3021 // Check that no extension objects have been created by calls to
3022 // eval from the current scope to the global scope.
3023 Result context(esi, this);
3024 Result tmp = allocator_->Allocate();
3025 ASSERT(tmp.is_valid()); // Called with all non-reserved registers available.
3026
3027 for (Scope* s = scope(); s != NULL; s = s->outer_scope()) {
3028 if (s->num_heap_slots() > 0) {
3029 if (s->calls_eval()) {
3030 // Check that extension is NULL.
3031 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX),
3032 Immediate(0));
3033 slow->Branch(not_equal, not_taken);
3034 }
3035 // Load next context in chain.
3036 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX));
3037 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset));
3038 context = tmp;
3039 }
3040 // If no outer scope calls eval, we do not need to check more
3041 // context extensions.
3042 if (!s->outer_scope_calls_eval()) break;
3043 }
3044 context.Unuse();
3045 tmp.Unuse();
3046
3047 // All extension objects were empty and it is safe to use a global
3048 // load IC call.
3049 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
3050 // Load the global object.
3051 LoadGlobal();
3052 // Setup the name register. All non-reserved registers are available.
3053 Result name = allocator_->Allocate(ecx);
3054 ASSERT(name.is_valid());
3055 __ mov(name.reg(), slot->var()->name());
3056 RelocInfo::Mode rmode = (typeof_state == INSIDE_TYPEOF)
3057 ? RelocInfo::CODE_TARGET
3058 : RelocInfo::CODE_TARGET_CONTEXT;
3059 Result answer = frame_->CallCodeObject(ic, rmode, &name, 0);
3060
3061 // Discard the global object. The result is in answer.
3062 frame_->Drop();
3063 return answer;
3064 }
3065
3066
2955 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { 3067 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
2956 if (slot->type() == Slot::LOOKUP) { 3068 if (slot->type() == Slot::LOOKUP) {
2957 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 3069 ASSERT(slot->var()->is_dynamic());
2958 3070
2959 // For now, just do a runtime call. 3071 // For now, just do a runtime call.
2960 frame_->Push(esi); 3072 frame_->Push(esi);
2961 frame_->Push(slot->var()->name()); 3073 frame_->Push(slot->var()->name());
2962 3074
2963 Result value(this); 3075 Result value(this);
2964 if (init_state == CONST_INIT) { 3076 if (init_state == CONST_INIT) {
2965 // Same as the case for a normal store, but ignores attribute 3077 // Same as the case for a normal store, but ignores attribute
2966 // (e.g. READ_ONLY) of context slot so that we can initialize const 3078 // (e.g. READ_ONLY) of context slot so that we can initialize const
2967 // properties (introduced via eval("const foo = (some expr);")). Also, 3079 // properties (introduced via eval("const foo = (some expr);")). Also,
(...skipping 11 matching lines...) Expand all
2979 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); 3091 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
2980 } else { 3092 } else {
2981 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); 3093 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3);
2982 } 3094 }
2983 // Storing a variable must keep the (new) value on the expression 3095 // Storing a variable must keep the (new) value on the expression
2984 // stack. This is necessary for compiling chained assignment 3096 // stack. This is necessary for compiling chained assignment
2985 // expressions. 3097 // expressions.
2986 frame_->Push(&value); 3098 frame_->Push(&value);
2987 3099
2988 } else { 3100 } else {
2989 ASSERT(slot->var()->mode() != Variable::DYNAMIC); 3101 ASSERT(!slot->var()->is_dynamic());
2990 3102
2991 JumpTarget exit(this); 3103 JumpTarget exit(this);
2992 if (init_state == CONST_INIT) { 3104 if (init_state == CONST_INIT) {
2993 ASSERT(slot->var()->mode() == Variable::CONST); 3105 ASSERT(slot->var()->mode() == Variable::CONST);
2994 // Only the first const initialization must be executed (the slot 3106 // Only the first const initialization must be executed (the slot
2995 // still contains 'the hole' value). When the assignment is executed, 3107 // still contains 'the hole' value). When the assignment is executed,
2996 // the code is identical to a normal store (see below). 3108 // the code is identical to a normal store (see below).
2997 // 3109 //
2998 // We spill the frame in the code below because the direct-frame 3110 // We spill the frame in the code below because the direct-frame
2999 // access of SlotOperand is potentially unsafe with an unspilled 3111 // access of SlotOperand is potentially unsafe with an unspilled
(...skipping 3543 matching lines...) Expand 10 before | Expand all | Expand 10 after
6543 6655
6544 // Slow-case: Go through the JavaScript implementation. 6656 // Slow-case: Go through the JavaScript implementation.
6545 __ bind(&slow); 6657 __ bind(&slow);
6546 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 6658 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
6547 } 6659 }
6548 6660
6549 6661
6550 #undef __ 6662 #undef __
6551 6663
6552 } } // namespace v8::internal 6664 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-ia32.h ('k') | src/contexts.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698