| 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 |