OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |