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

Side by Side Diff: src/runtime.cc

Issue 8097: Fix issue 124 by computing the receiver correctly when... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 12 years, 2 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/objects-inl.h ('k') | test/mjsunit/bugs/bug-124.js » ('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 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 static_cast<PropertyAttributes>(Smi::cast(args[2])->value()); 467 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
468 ASSERT(mode == READ_ONLY || mode == NONE); 468 ASSERT(mode == READ_ONLY || mode == NONE);
469 Handle<Object> initial_value(args[3]); 469 Handle<Object> initial_value(args[3]);
470 470
471 // Declarations are always done in the function context. 471 // Declarations are always done in the function context.
472 context = Handle<Context>(context->fcontext()); 472 context = Handle<Context>(context->fcontext());
473 473
474 int index; 474 int index;
475 PropertyAttributes attributes; 475 PropertyAttributes attributes;
476 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 476 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
477 Handle<Object> context_obj = 477 Handle<Object> holder =
478 context->Lookup(name, flags, &index, &attributes); 478 context->Lookup(name, flags, &index, &attributes);
479 479
480 if (attributes != ABSENT) { 480 if (attributes != ABSENT) {
481 // The name was declared before; check for conflicting 481 // The name was declared before; check for conflicting
482 // re-declarations: This is similar to the code in parser.cc in 482 // re-declarations: This is similar to the code in parser.cc in
483 // the AstBuildingParser::Declare function. 483 // the AstBuildingParser::Declare function.
484 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { 484 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
485 // Functions are not read-only. 485 // Functions are not read-only.
486 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); 486 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
487 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; 487 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
488 return ThrowRedeclarationError(type, name); 488 return ThrowRedeclarationError(type, name);
489 } 489 }
490 490
491 // Initialize it if necessary. 491 // Initialize it if necessary.
492 if (*initial_value != NULL) { 492 if (*initial_value != NULL) {
493 if (index >= 0) { 493 if (index >= 0) {
494 // The variable or constant context slot should always be in 494 // The variable or constant context slot should always be in
495 // the function context; not in any outer context nor in the 495 // the function context; not in any outer context nor in the
496 // arguments object. 496 // arguments object.
497 ASSERT(context_obj.is_identical_to(context)); 497 ASSERT(holder.is_identical_to(context));
498 if (((attributes & READ_ONLY) == 0) || 498 if (((attributes & READ_ONLY) == 0) ||
499 context->get(index)->IsTheHole()) { 499 context->get(index)->IsTheHole()) {
500 context->set(index, *initial_value); 500 context->set(index, *initial_value);
501 } 501 }
502 } else { 502 } else {
503 // Slow case: The property is not in the FixedArray part of the context. 503 // Slow case: The property is not in the FixedArray part of the context.
504 Handle<JSObject> context_ext = Handle<JSObject>::cast(context_obj); 504 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
505 SetProperty(context_ext, name, initial_value, mode); 505 SetProperty(context_ext, name, initial_value, mode);
506 } 506 }
507 } 507 }
508 508
509 } else { 509 } else {
510 // The property is not in the function context. It needs to be 510 // The property is not in the function context. It needs to be
511 // "declared" in the function context's extension context, or in the 511 // "declared" in the function context's extension context, or in the
512 // global context. 512 // global context.
513 Handle<JSObject> context_ext; 513 Handle<JSObject> context_ext;
514 if (context->extension() != NULL) { 514 if (context->extension() != NULL) {
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 ASSERT(!value->IsTheHole()); 695 ASSERT(!value->IsTheHole());
696 CONVERT_ARG_CHECKED(Context, context, 1); 696 CONVERT_ARG_CHECKED(Context, context, 1);
697 Handle<String> name(String::cast(args[2])); 697 Handle<String> name(String::cast(args[2]));
698 698
699 // Initializations are always done in the function context. 699 // Initializations are always done in the function context.
700 context = Handle<Context>(context->fcontext()); 700 context = Handle<Context>(context->fcontext());
701 701
702 int index; 702 int index;
703 PropertyAttributes attributes; 703 PropertyAttributes attributes;
704 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 704 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
705 Handle<Object> context_obj = 705 Handle<Object> holder =
706 context->Lookup(name, flags, &index, &attributes); 706 context->Lookup(name, flags, &index, &attributes);
707 707
708 // The property should always be present. It is always declared 708 // The property should always be present. It is always declared
709 // before being initialized through DeclareContextSlot. 709 // before being initialized through DeclareContextSlot.
710 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0); 710 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
711 711
712 // If the slot is in the context, we set it but only if it hasn't 712 // If the slot is in the context, we set it but only if it hasn't
713 // been set before. 713 // been set before.
714 if (index >= 0) { 714 if (index >= 0) {
715 // The constant context slot should always be in the function 715 // The constant context slot should always be in the function
716 // context; not in any outer context nor in the arguments object. 716 // context; not in any outer context nor in the arguments object.
717 ASSERT(context_obj.is_identical_to(context)); 717 ASSERT(holder.is_identical_to(context));
718 if (context->get(index)->IsTheHole()) { 718 if (context->get(index)->IsTheHole()) {
719 context->set(index, *value); 719 context->set(index, *value);
720 } 720 }
721 return *value; 721 return *value;
722 } 722 }
723 723
724 // Otherwise, the slot must be in a JS object extension. 724 // Otherwise, the slot must be in a JS object extension.
725 Handle<JSObject> context_ext(JSObject::cast(*context_obj)); 725 Handle<JSObject> context_ext(JSObject::cast(*holder));
726 726
727 // We must initialize the value only if it wasn't initialized 727 // We must initialize the value only if it wasn't initialized
728 // before, e.g. for const declarations in a loop. The property has 728 // before, e.g. for const declarations in a loop. The property has
729 // the hole value if it wasn't initialized yet. NOTE: We cannot use 729 // the hole value if it wasn't initialized yet. NOTE: We cannot use
730 // GetProperty() to get the current value as it 'unholes' the value. 730 // GetProperty() to get the current value as it 'unholes' the value.
731 LookupResult lookup; 731 LookupResult lookup;
732 context_ext->LocalLookupRealNamedProperty(*name, &lookup); 732 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
733 ASSERT(lookup.IsProperty()); // the property was declared 733 ASSERT(lookup.IsProperty()); // the property was declared
734 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only 734 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
735 735
(...skipping 2558 matching lines...) Expand 10 before | Expand all | Expand 10 after
3294 static Object* Runtime_LookupContext(Arguments args) { 3294 static Object* Runtime_LookupContext(Arguments args) {
3295 HandleScope scope; 3295 HandleScope scope;
3296 ASSERT(args.length() == 2); 3296 ASSERT(args.length() == 2);
3297 3297
3298 CONVERT_ARG_CHECKED(Context, context, 0); 3298 CONVERT_ARG_CHECKED(Context, context, 0);
3299 CONVERT_ARG_CHECKED(String, name, 1); 3299 CONVERT_ARG_CHECKED(String, name, 1);
3300 3300
3301 int index; 3301 int index;
3302 PropertyAttributes attributes; 3302 PropertyAttributes attributes;
3303 ContextLookupFlags flags = FOLLOW_CHAINS; 3303 ContextLookupFlags flags = FOLLOW_CHAINS;
3304 Handle<Object> context_obj = 3304 Handle<Object> holder =
3305 context->Lookup(name, flags, &index, &attributes); 3305 context->Lookup(name, flags, &index, &attributes);
3306 3306
3307 if (index < 0 && *context_obj != NULL) { 3307 if (index < 0 && *holder != NULL) {
3308 ASSERT(context_obj->IsJSObject()); 3308 ASSERT(holder->IsJSObject());
3309 return *context_obj; 3309 return *holder;
3310 } 3310 }
3311 3311
3312 // No intermediate context found. Use global object by default. 3312 // No intermediate context found. Use global object by default.
3313 return Top::context()->global(); 3313 return Top::context()->global();
3314 } 3314 }
3315 3315
3316 3316
3317 // A mechanism to return pairs of Object*'s. This is somewhat 3317 // A mechanism to return pairs of Object*'s. This is somewhat
3318 // compiler-dependent as it assumes that a 64-bit value (a long long) 3318 // compiler-dependent as it assumes that a 64-bit value (a long long)
3319 // is returned via two registers (edx:eax on ia32). Both the ia32 and 3319 // is returned via two registers (edx:eax on ia32). Both the ia32 and
3320 // arm platform support this; it is mostly an issue of "coaxing" the 3320 // arm platform support this; it is mostly an issue of "coaxing" the
3321 // compiler to do the right thing. 3321 // compiler to do the right thing.
3322 // 3322 //
3323 // TODO(1236026): This is a non-portable hack that should be removed. 3323 // TODO(1236026): This is a non-portable hack that should be removed.
3324 typedef uint64_t ObjPair; 3324 typedef uint64_t ObjPair;
3325 ObjPair MakePair(Object* x, Object* y) { 3325 ObjPair MakePair(Object* x, Object* y) {
3326 return reinterpret_cast<uint32_t>(x) | 3326 return reinterpret_cast<uint32_t>(x) |
3327 (reinterpret_cast<ObjPair>(y) << 32); 3327 (reinterpret_cast<ObjPair>(y) << 32);
3328 } 3328 }
3329 3329
3330 3330
3331 static Object* Unhole(Object* x, PropertyAttributes attributes) { 3331 static Object* Unhole(Object* x, PropertyAttributes attributes) {
3332 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); 3332 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
3333 USE(attributes); 3333 USE(attributes);
3334 return x->IsTheHole() ? Heap::undefined_value() : x; 3334 return x->IsTheHole() ? Heap::undefined_value() : x;
3335 } 3335 }
3336 3336
3337 3337
3338 static Object* ComputeContextSlotReceiver(Object* holder) {
3339 // If the "property" we were looking for is a local variable or an
3340 // argument in a context, the receiver is the global object; see
3341 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
3342 HeapObject* object = HeapObject::cast(holder);
3343 Context* top = Top::context();
3344 if (holder->IsContext()) return top->global()->global_receiver();
3345
3346 // TODO(xxx): Find a better - and faster way - of checking for
3347 // arguments and context extension objects. This kinda sucks.
3348 JSFunction* context_extension_function =
3349 top->global_context()->context_extension_function();
3350 JSObject* arguments_boilerplate =
3351 top->global_context()->arguments_boilerplate();
3352 JSFunction* arguments_function =
3353 JSFunction::cast(arguments_boilerplate->map()->constructor());
3354 // If the holder is an arguments object or a context extension then the
3355 // receiver is also the global object;
3356 Object* constructor = HeapObject::cast(holder)->map()->constructor();
3357 if (constructor == context_extension_function ||
3358 constructor == arguments_function) {
3359 return Top::context()->global()->global_receiver();
3360 }
3361
3362 // If the holder is a global object, we have to be careful to wrap
3363 // it in its proxy if necessary.
3364 if (object->IsGlobalObject()) {
3365 return GlobalObject::cast(object)->global_receiver();
3366 } else {
3367 return object;
3368 }
3369 }
3370
3371
3338 static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) { 3372 static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) {
3339 HandleScope scope; 3373 HandleScope scope;
3340 ASSERT(args.length() == 2); 3374 ASSERT(args.length() == 2);
3341 3375
3342 if (!args[0]->IsContext()) return MakePair(IllegalOperation(), NULL); 3376 if (!args[0]->IsContext()) return MakePair(IllegalOperation(), NULL);
3343 Handle<Context> context = args.at<Context>(0); 3377 Handle<Context> context = args.at<Context>(0);
3344 Handle<String> name(String::cast(args[1])); 3378 Handle<String> name(String::cast(args[1]));
3345 3379
3346 int index; 3380 int index;
3347 PropertyAttributes attributes; 3381 PropertyAttributes attributes;
3348 ContextLookupFlags flags = FOLLOW_CHAINS; 3382 ContextLookupFlags flags = FOLLOW_CHAINS;
3349 Handle<Object> context_obj = 3383 Handle<Object> holder =
3350 context->Lookup(name, flags, &index, &attributes); 3384 context->Lookup(name, flags, &index, &attributes);
3351 3385
3352 if (index >= 0) { 3386 if (index >= 0) {
3353 if (context_obj->IsContext()) { 3387 Handle<Object> receiver =
3354 // The context is an Execution context, and the "property" we were looking 3388 Handle<Object>(ComputeContextSlotReceiver(*holder));
3355 // for is a local variable in that context. According to ECMA-262, 3rd., 3389 Handle<Object> value;
3356 // 10.1.6 and 10.2.3, the receiver is the global object. 3390 if (holder->IsContext()) {
3357 return MakePair( 3391 value = Handle<Object>(Context::cast(*holder)->get(index));
3358 Unhole(Handle<Context>::cast(context_obj)->get(index), attributes),
3359 Top::context()->global());
3360 } else { 3392 } else {
3361 return MakePair( 3393 // Arguments object.
3362 Unhole(Handle<JSObject>::cast(context_obj)->GetElement(index), 3394 value = Handle<Object>(JSObject::cast(*holder)->GetElement(index));
3363 attributes),
3364 *context_obj);
3365 } 3395 }
3396 return MakePair(Unhole(*value, attributes), *receiver);
3366 } 3397 }
3367 3398
3368 if (*context_obj != NULL) { 3399 if (*holder != NULL) {
3369 ASSERT(Handle<JSObject>::cast(context_obj)->HasProperty(*name)); 3400 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
3370 // Note: As of 5/29/2008, GetProperty does the "unholing" and so this call 3401 // Note: As of 5/29/2008, GetProperty does the "unholing" and so
3371 // here is redundant. We left it anyway, to be explicit; also it's not clear 3402 // this call here is redundant. We left it anyway, to be explicit;
3372 // why GetProperty should do the unholing in the first place. 3403 // also it's not clear why GetProperty should do the unholing in
3404 // the first place.
3373 return MakePair( 3405 return MakePair(
3374 Unhole(Handle<JSObject>::cast(context_obj)->GetProperty(*name), 3406 Unhole(Handle<JSObject>::cast(holder)->GetProperty(*name),
3375 attributes), 3407 attributes),
3376 *context_obj); 3408 ComputeContextSlotReceiver(*holder));
3377 } 3409 }
3378 3410
3379 if (throw_error) { 3411 if (throw_error) {
3380 // The property doesn't exist - throw exception. 3412 // The property doesn't exist - throw exception.
3381 Handle<Object> reference_error = 3413 Handle<Object> reference_error =
3382 Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); 3414 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3383 return MakePair(Top::Throw(*reference_error), NULL); 3415 return MakePair(Top::Throw(*reference_error), NULL);
3384 } else { 3416 } else {
3385 // The property doesn't exist - return undefined 3417 // The property doesn't exist - return undefined
3386 return MakePair(Heap::undefined_value(), Heap::undefined_value()); 3418 return MakePair(Heap::undefined_value(), Heap::undefined_value());
(...skipping 15 matching lines...) Expand all
3402 HandleScope scope; 3434 HandleScope scope;
3403 ASSERT(args.length() == 3); 3435 ASSERT(args.length() == 3);
3404 3436
3405 Handle<Object> value(args[0]); 3437 Handle<Object> value(args[0]);
3406 CONVERT_ARG_CHECKED(Context, context, 1); 3438 CONVERT_ARG_CHECKED(Context, context, 1);
3407 CONVERT_ARG_CHECKED(String, name, 2); 3439 CONVERT_ARG_CHECKED(String, name, 2);
3408 3440
3409 int index; 3441 int index;
3410 PropertyAttributes attributes; 3442 PropertyAttributes attributes;
3411 ContextLookupFlags flags = FOLLOW_CHAINS; 3443 ContextLookupFlags flags = FOLLOW_CHAINS;
3412 Handle<Object> context_obj = 3444 Handle<Object> holder =
3413 context->Lookup(name, flags, &index, &attributes); 3445 context->Lookup(name, flags, &index, &attributes);
3414 3446
3415 if (index >= 0) { 3447 if (index >= 0) {
3416 if (context_obj->IsContext()) { 3448 if (holder->IsContext()) {
3417 // Ignore if read_only variable. 3449 // Ignore if read_only variable.
3418 if ((attributes & READ_ONLY) == 0) { 3450 if ((attributes & READ_ONLY) == 0) {
3419 Handle<Context>::cast(context_obj)->set(index, *value); 3451 Handle<Context>::cast(holder)->set(index, *value);
3420 } 3452 }
3421 } else { 3453 } else {
3422 ASSERT((attributes & READ_ONLY) == 0); 3454 ASSERT((attributes & READ_ONLY) == 0);
3423 Object* result = 3455 Object* result =
3424 Handle<JSObject>::cast(context_obj)->SetElement(index, *value); 3456 Handle<JSObject>::cast(holder)->SetElement(index, *value);
3425 USE(result); 3457 USE(result);
3426 ASSERT(!result->IsFailure()); 3458 ASSERT(!result->IsFailure());
3427 } 3459 }
3428 return *value; 3460 return *value;
3429 } 3461 }
3430 3462
3431 // Slow case: The property is not in a FixedArray context. 3463 // Slow case: The property is not in a FixedArray context.
3432 // It is either in an JSObject extension context or it was not found. 3464 // It is either in an JSObject extension context or it was not found.
3433 Handle<JSObject> context_ext; 3465 Handle<JSObject> context_ext;
3434 3466
3435 if (*context_obj != NULL) { 3467 if (*holder != NULL) {
3436 // The property exists in the extension context. 3468 // The property exists in the extension context.
3437 context_ext = Handle<JSObject>::cast(context_obj); 3469 context_ext = Handle<JSObject>::cast(holder);
3438 } else { 3470 } else {
3439 // The property was not found. It needs to be stored in the global context. 3471 // The property was not found. It needs to be stored in the global context.
3440 ASSERT(attributes == ABSENT); 3472 ASSERT(attributes == ABSENT);
3441 attributes = NONE; 3473 attributes = NONE;
3442 context_ext = Handle<JSObject>(Top::context()->global()); 3474 context_ext = Handle<JSObject>(Top::context()->global());
3443 } 3475 }
3444 3476
3445 // Set the property, but ignore if read_only variable. 3477 // Set the property, but ignore if read_only variable.
3446 if ((attributes & READ_ONLY) == 0) { 3478 if ((attributes & READ_ONLY) == 0) {
3447 Handle<Object> set = SetProperty(context_ext, name, value, attributes); 3479 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
(...skipping 2002 matching lines...) Expand 10 before | Expand all | Expand 10 after
5450 5482
5451 void Runtime::PerformGC(Object* result) { 5483 void Runtime::PerformGC(Object* result) {
5452 Failure* failure = Failure::cast(result); 5484 Failure* failure = Failure::cast(result);
5453 // Try to do a garbage collection; ignore it if it fails. The C 5485 // Try to do a garbage collection; ignore it if it fails. The C
5454 // entry stub will throw an out-of-memory exception in that case. 5486 // entry stub will throw an out-of-memory exception in that case.
5455 Heap::CollectGarbage(failure->requested(), failure->allocation_space()); 5487 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
5456 } 5488 }
5457 5489
5458 5490
5459 } } // namespace v8::internal 5491 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects-inl.h ('k') | test/mjsunit/bugs/bug-124.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698