00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "v8.h"
00029
00030 #include "api.h"
00031 #include "bootstrapper.h"
00032 #include "debug.h"
00033 #include "execution.h"
00034 #include "objects-inl.h"
00035 #include "macro-assembler.h"
00036 #include "scanner.h"
00037 #include "scopeinfo.h"
00038 #include "string-stream.h"
00039
00040 #ifdef ENABLE_DISASSEMBLER
00041 #include "disassembler.h"
00042 #endif
00043
00044 namespace v8 { namespace internal {
00045
00046
00047
00048 const int kGetterIndex = 0;
00049 const int kSetterIndex = 1;
00050
00051 bool Object::IsInstanceOf(FunctionTemplateInfo* expected) {
00052
00053 if (!this->IsJSObject()) return false;
00054
00055 Object* cons_obj = JSObject::cast(this)->map()->constructor();
00056 if (!cons_obj->IsJSFunction()) return false;
00057 JSFunction* fun = JSFunction::cast(cons_obj);
00058
00059
00060 for (Object* type = fun->shared()->function_data();
00061 type->IsFunctionTemplateInfo();
00062 type = FunctionTemplateInfo::cast(type)->parent_template()) {
00063 if (type == expected) return true;
00064 }
00065
00066 return false;
00067 }
00068
00069
00070 static Object* CreateJSValue(JSFunction* constructor, Object* value) {
00071 Object* result = Heap::AllocateJSObject(constructor);
00072 if (result->IsFailure()) return result;
00073 JSValue::cast(result)->set_value(value);
00074 return result;
00075 }
00076
00077
00078 Object* Object::ToObject(Context* global_context) {
00079 if (IsNumber()) {
00080 return CreateJSValue(global_context->number_function(), this);
00081 } else if (IsBoolean()) {
00082 return CreateJSValue(global_context->boolean_function(), this);
00083 } else if (IsString()) {
00084 return CreateJSValue(global_context->string_function(), this);
00085 }
00086 ASSERT(IsJSObject());
00087 return this;
00088 }
00089
00090
00091 Object* Object::ToObject() {
00092 Context* global_context = Top::context()->global_context();
00093 if (IsJSObject()) {
00094 return this;
00095 } else if (IsNumber()) {
00096 return CreateJSValue(global_context->number_function(), this);
00097 } else if (IsBoolean()) {
00098 return CreateJSValue(global_context->boolean_function(), this);
00099 } else if (IsString()) {
00100 return CreateJSValue(global_context->string_function(), this);
00101 }
00102
00103
00104 return Failure::InternalError();
00105 }
00106
00107
00108 Object* Object::ToBoolean() {
00109 if (IsTrue()) return Heap::true_value();
00110 if (IsFalse()) return Heap::false_value();
00111 if (IsSmi()) {
00112 return Heap::ToBoolean(Smi::cast(this)->value() != 0);
00113 }
00114 if (IsUndefined() || IsNull()) return Heap::false_value();
00115
00116 if (IsUndetectableObject()) {
00117 return Heap::false_value();
00118 }
00119 if (IsString()) {
00120 return Heap::ToBoolean(String::cast(this)->length() != 0);
00121 }
00122 if (IsHeapNumber()) {
00123 return HeapNumber::cast(this)->HeapNumberToBoolean();
00124 }
00125 return Heap::true_value();
00126 }
00127
00128
00129 void Object::Lookup(String* name, LookupResult* result) {
00130 if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result);
00131 Object* holder = NULL;
00132 Context* global_context = Top::context()->global_context();
00133 if (IsString()) {
00134 holder = global_context->string_function()->instance_prototype();
00135 } else if (IsNumber()) {
00136 holder = global_context->number_function()->instance_prototype();
00137 } else if (IsBoolean()) {
00138 holder = global_context->boolean_function()->instance_prototype();
00139 }
00140 ASSERT(holder != NULL);
00141 JSObject::cast(holder)->Lookup(name, result);
00142 }
00143
00144
00145 Object* Object::GetPropertyWithReceiver(Object* receiver,
00146 String* name,
00147 PropertyAttributes* attributes) {
00148 LookupResult result;
00149 Lookup(name, &result);
00150 return GetProperty(receiver, &result, name, attributes);
00151 }
00152
00153
00154 Object* Object::GetPropertyWithCallback(Object* receiver,
00155 Object* structure,
00156 String* name,
00157 Object* holder) {
00158
00159
00160
00161 if (structure->IsProxy()) {
00162 AccessorDescriptor* callback =
00163 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
00164 Object* value = (callback->getter)(receiver, callback->data);
00165 RETURN_IF_SCHEDULED_EXCEPTION();
00166 return value;
00167 }
00168
00169
00170 if (structure->IsAccessorInfo()) {
00171 AccessorInfo* data = AccessorInfo::cast(structure);
00172 Object* fun_obj = data->getter();
00173 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
00174 HandleScope scope;
00175 Handle<JSObject> self(JSObject::cast(receiver));
00176 Handle<JSObject> holder_handle(JSObject::cast(holder));
00177 Handle<String> key(name);
00178 Handle<Object> fun_data(data->data());
00179 LOG(ApiNamedPropertyAccess("load", *self, name));
00180 v8::AccessorInfo info(v8::Utils::ToLocal(self),
00181 v8::Utils::ToLocal(fun_data),
00182 v8::Utils::ToLocal(holder_handle));
00183 v8::Handle<v8::Value> result;
00184 {
00185
00186 VMState state(OTHER);
00187 result = call_fun(v8::Utils::ToLocal(key), info);
00188 }
00189 RETURN_IF_SCHEDULED_EXCEPTION();
00190 if (result.IsEmpty()) return Heap::undefined_value();
00191 return *v8::Utils::OpenHandle(*result);
00192 }
00193
00194
00195 if (structure->IsFixedArray()) {
00196 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
00197 if (getter->IsJSFunction()) {
00198 HandleScope scope;
00199 Handle<JSFunction> fun(JSFunction::cast(getter));
00200 Handle<Object> self(receiver);
00201 bool has_pending_exception;
00202 Object* result =
00203 *Execution::Call(fun, self, 0, NULL, &has_pending_exception);
00204
00205 if (has_pending_exception) return Failure::Exception();
00206 return result;
00207 }
00208
00209 return Heap::undefined_value();
00210 }
00211
00212 UNREACHABLE();
00213 return 0;
00214 }
00215
00216
00217
00218 Object* JSObject::GetPropertyWithFailedAccessCheck(Object* receiver,
00219 LookupResult* result,
00220 String* name) {
00221 if (result->IsValid()) {
00222 switch (result->type()) {
00223 case CALLBACKS: {
00224
00225 Object* obj = result->GetCallbackObject();
00226 if (obj->IsAccessorInfo()) {
00227 AccessorInfo* info = AccessorInfo::cast(obj);
00228 if (info->all_can_read()) {
00229 return GetPropertyWithCallback(receiver,
00230 result->GetCallbackObject(),
00231 name,
00232 result->holder());
00233 }
00234 }
00235 break;
00236 }
00237 case NORMAL:
00238 case FIELD:
00239 case CONSTANT_FUNCTION: {
00240
00241 LookupResult r;
00242 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
00243 if (r.IsValid()) {
00244 return GetPropertyWithFailedAccessCheck(receiver, &r, name);
00245 }
00246 break;
00247 }
00248 case INTERCEPTOR: {
00249
00250
00251 LookupResult r;
00252 result->holder()->LookupRealNamedProperty(name, &r);
00253 if (r.IsValid()) {
00254 return GetPropertyWithFailedAccessCheck(receiver, &r, name);
00255 }
00256 break;
00257 }
00258 default: {
00259 break;
00260 }
00261 }
00262 }
00263
00264 Top::ReportFailedAccessCheck(this, v8::ACCESS_GET);
00265 return Heap::undefined_value();
00266 }
00267
00268
00269 Object* JSObject::GetLazyProperty(Object* receiver,
00270 LookupResult* result,
00271 String* name,
00272 PropertyAttributes* attributes) {
00273 HandleScope scope;
00274 Handle<Object> this_handle(this);
00275 Handle<Object> receiver_handle(receiver);
00276 Handle<String> name_handle(name);
00277 bool pending_exception;
00278 LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
00279 &pending_exception);
00280 if (pending_exception) return Failure::Exception();
00281 return this_handle->GetPropertyWithReceiver(*receiver_handle,
00282 *name_handle,
00283 attributes);
00284 }
00285
00286
00287 Object* JSObject::SetLazyProperty(LookupResult* result,
00288 String* name,
00289 Object* value,
00290 PropertyAttributes attributes) {
00291 ASSERT(!IsJSGlobalProxy());
00292 HandleScope scope;
00293 Handle<JSObject> this_handle(this);
00294 Handle<String> name_handle(name);
00295 Handle<Object> value_handle(value);
00296 bool pending_exception;
00297 LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
00298 &pending_exception);
00299 if (pending_exception) return Failure::Exception();
00300 return this_handle->SetProperty(*name_handle, *value_handle, attributes);
00301 }
00302
00303
00304 Object* JSObject::DeleteLazyProperty(LookupResult* result, String* name) {
00305 HandleScope scope;
00306 Handle<JSObject> this_handle(this);
00307 Handle<String> name_handle(name);
00308 bool pending_exception;
00309 LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
00310 &pending_exception);
00311 if (pending_exception) return Failure::Exception();
00312 return this_handle->DeleteProperty(*name_handle);
00313 }
00314
00315
00316 Object* Object::GetProperty(Object* receiver,
00317 LookupResult* result,
00318 String* name,
00319 PropertyAttributes* attributes) {
00320
00321
00322 AssertNoContextChange ncc;
00323
00324
00325
00326
00327
00328
00329
00330 Object* last = result->IsValid() ? result->holder() : Heap::null_value();
00331 for (Object* current = this; true; current = current->GetPrototype()) {
00332 if (current->IsAccessCheckNeeded()) {
00333
00334
00335
00336
00337 JSObject* checked = JSObject::cast(current);
00338 if (!Top::MayNamedAccess(checked, name, v8::ACCESS_GET)) {
00339 return checked->GetPropertyWithFailedAccessCheck(receiver,
00340 result,
00341 name);
00342 }
00343 }
00344
00345
00346
00347 if (current == last) break;
00348 }
00349
00350 if (!result->IsProperty()) {
00351 *attributes = ABSENT;
00352 return Heap::undefined_value();
00353 }
00354 *attributes = result->GetAttributes();
00355 if (!result->IsLoaded()) {
00356 return JSObject::cast(this)->GetLazyProperty(receiver,
00357 result,
00358 name,
00359 attributes);
00360 }
00361 Object* value;
00362 JSObject* holder = result->holder();
00363 switch (result->type()) {
00364 case NORMAL:
00365 value =
00366 holder->property_dictionary()->ValueAt(result->GetDictionaryEntry());
00367 ASSERT(!value->IsTheHole() || result->IsReadOnly());
00368 return value->IsTheHole() ? Heap::undefined_value() : value;
00369 case FIELD:
00370 value = holder->FastPropertyAt(result->GetFieldIndex());
00371 ASSERT(!value->IsTheHole() || result->IsReadOnly());
00372 return value->IsTheHole() ? Heap::undefined_value() : value;
00373 case CONSTANT_FUNCTION:
00374 return result->GetConstantFunction();
00375 case CALLBACKS:
00376 return GetPropertyWithCallback(receiver,
00377 result->GetCallbackObject(),
00378 name,
00379 holder);
00380 case INTERCEPTOR: {
00381 JSObject* recvr = JSObject::cast(receiver);
00382 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
00383 }
00384 default:
00385 UNREACHABLE();
00386 return NULL;
00387 }
00388 }
00389
00390
00391 Object* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
00392
00393 if (!IsJSObject()) return Heap::undefined_value();
00394 return JSObject::cast(this)->GetElementWithReceiver(JSObject::cast(receiver),
00395 index);
00396 }
00397
00398
00399 Object* Object::GetPrototype() {
00400
00401 if (IsJSObject()) return JSObject::cast(this)->map()->prototype();
00402 Context* context = Top::context()->global_context();
00403
00404 if (IsNumber()) return context->number_function()->instance_prototype();
00405 if (IsString()) return context->string_function()->instance_prototype();
00406 if (IsBoolean()) {
00407 return context->boolean_function()->instance_prototype();
00408 } else {
00409 return Heap::null_value();
00410 }
00411 }
00412
00413
00414 void Object::ShortPrint() {
00415 HeapStringAllocator allocator;
00416 StringStream accumulator(&allocator);
00417 ShortPrint(&accumulator);
00418 accumulator.OutputToStdOut();
00419 }
00420
00421
00422 void Object::ShortPrint(StringStream* accumulator) {
00423 if (IsSmi()) {
00424 Smi::cast(this)->SmiPrint(accumulator);
00425 } else if (IsFailure()) {
00426 Failure::cast(this)->FailurePrint(accumulator);
00427 } else {
00428 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
00429 }
00430 }
00431
00432
00433 void Smi::SmiPrint() {
00434 PrintF("%d", value());
00435 }
00436
00437
00438 void Smi::SmiPrint(StringStream* accumulator) {
00439 accumulator->Add("%d", value());
00440 }
00441
00442
00443 void Failure::FailurePrint(StringStream* accumulator) {
00444 accumulator->Add("Failure(%d)", value());
00445 }
00446
00447
00448 void Failure::FailurePrint() {
00449 PrintF("Failure(%d)", value());
00450 }
00451
00452
00453 Failure* Failure::RetryAfterGC(int requested_bytes, AllocationSpace space) {
00454 ASSERT((space & ~kSpaceTagMask) == 0);
00455 int requested = requested_bytes >> kObjectAlignmentBits;
00456 int value = (requested << kSpaceTagSize) | space;
00457
00458
00459
00460
00461 if (value >> kSpaceTagSize != requested ||
00462 !Smi::IsValid(value) ||
00463 value != ((value << kFailureTypeTagSize) >> kFailureTypeTagSize) ||
00464 !Smi::IsValid(value << kFailureTypeTagSize)) {
00465 Top::context()->mark_out_of_memory();
00466 return Failure::OutOfMemoryException();
00467 }
00468 return Construct(RETRY_AFTER_GC, value);
00469 }
00470
00471
00472
00473
00474
00475
00476
00477 static bool AnWord(String* str) {
00478 if (str->length() == 0) return false;
00479 int c0 = str->Get(0);
00480 int c1 = str->length() > 1 ? str->Get(1) : 0;
00481 if (c0 == 'U') {
00482 if (c1 > 'Z') {
00483 return true;
00484 }
00485 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
00486 return true;
00487 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
00488 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
00489 c0 == 'S' || c0 == 'X')) {
00490 return true;
00491 }
00492 return false;
00493 }
00494
00495
00496 Object* String::Flatten() {
00497 #ifdef DEBUG
00498
00499
00500
00501
00502 if (!Heap::IsAllocationAllowed()) return this;
00503 #endif
00504
00505 switch (representation_tag()) {
00506 case kSlicedStringTag: {
00507 SlicedString* ss = SlicedString::cast(this);
00508
00509
00510
00511 ASSERT(!ss->buffer()->IsSlicedString());
00512 Object* ok = String::cast(ss->buffer())->Flatten();
00513 if (ok->IsFailure()) return ok;
00514
00515
00516
00517 if (String::cast(ok)->StringIsConsString()) {
00518 ss->set_buffer(ConsString::cast(ok)->first());
00519 }
00520 return this;
00521 }
00522 case kConsStringTag: {
00523 ConsString* cs = ConsString::cast(this);
00524 if (String::cast(cs->second())->length() == 0) {
00525 return this;
00526 }
00527
00528
00529
00530 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED;
00531 int len = length();
00532 Object* object;
00533 String* result;
00534 if (IsAsciiRepresentation()) {
00535 object = Heap::AllocateRawAsciiString(len, tenure);
00536 if (object->IsFailure()) return object;
00537 result = String::cast(object);
00538 String* first = String::cast(cs->first());
00539 int first_length = first->length();
00540 char* dest = SeqAsciiString::cast(result)->GetChars();
00541 WriteToFlat(first, dest, 0, first_length);
00542 WriteToFlat(String::cast(cs->second()),
00543 dest + first_length,
00544 0,
00545 len - first_length);
00546 } else {
00547 object = Heap::AllocateRawTwoByteString(len, tenure);
00548 if (object->IsFailure()) return object;
00549 result = String::cast(object);
00550 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
00551 String* first = String::cast(cs->first());
00552 int first_length = first->length();
00553 WriteToFlat(first, dest, 0, first_length);
00554 WriteToFlat(String::cast(cs->second()),
00555 dest + first_length,
00556 0,
00557 len - first_length);
00558 }
00559 cs->set_first(result);
00560 cs->set_second(Heap::empty_string());
00561 return this;
00562 }
00563 default:
00564 return this;
00565 }
00566 }
00567
00568
00569 void String::StringShortPrint(StringStream* accumulator) {
00570 int len = length();
00571 if (len > kMaxMediumStringSize) {
00572 accumulator->Add("<Very long string[%u]>", len);
00573 return;
00574 }
00575
00576 if (!LooksValid()) {
00577 accumulator->Add("<Invalid String>");
00578 return;
00579 }
00580
00581 StringInputBuffer buf(this);
00582
00583 bool truncated = false;
00584 if (len > kMaxShortPrintLength) {
00585 len = kMaxShortPrintLength;
00586 truncated = true;
00587 }
00588 bool ascii = true;
00589 for (int i = 0; i < len; i++) {
00590 int c = buf.GetNext();
00591
00592 if (c < 32 || c >= 127) {
00593 ascii = false;
00594 }
00595 }
00596 buf.Reset(this);
00597 if (ascii) {
00598 accumulator->Add("<String[%u]: ", length());
00599 for (int i = 0; i < len; i++) {
00600 accumulator->Put(buf.GetNext());
00601 }
00602 accumulator->Put('>');
00603 } else {
00604
00605
00606 accumulator->Add("<String[%u]\\: ", length());
00607 for (int i = 0; i < len; i++) {
00608 int c = buf.GetNext();
00609 if (c == '\n') {
00610 accumulator->Add("\\n");
00611 } else if (c == '\r') {
00612 accumulator->Add("\\r");
00613 } else if (c == '\\') {
00614 accumulator->Add("\\\\");
00615 } else if (c < 32 || c > 126) {
00616 accumulator->Add("\\x%02x", c);
00617 } else {
00618 accumulator->Put(c);
00619 }
00620 }
00621 if (truncated) {
00622 accumulator->Put('.');
00623 accumulator->Put('.');
00624 accumulator->Put('.');
00625 }
00626 accumulator->Put('>');
00627 }
00628 return;
00629 }
00630
00631
00632 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
00633 switch (map()->instance_type()) {
00634 case JS_ARRAY_TYPE: {
00635 double length = JSArray::cast(this)->length()->Number();
00636 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
00637 break;
00638 }
00639 case JS_REGEXP_TYPE: {
00640 accumulator->Add("<JS RegExp>");
00641 break;
00642 }
00643 case JS_FUNCTION_TYPE: {
00644 Object* fun_name = JSFunction::cast(this)->shared()->name();
00645 bool printed = false;
00646 if (fun_name->IsString()) {
00647 String* str = String::cast(fun_name);
00648 if (str->length() > 0) {
00649 accumulator->Add("<JS Function ");
00650 accumulator->Put(str);
00651 accumulator->Put('>');
00652 printed = true;
00653 }
00654 }
00655 if (!printed) {
00656 accumulator->Add("<JS Function>");
00657 }
00658 break;
00659 }
00660
00661
00662 default: {
00663 Object* constructor = map()->constructor();
00664 bool printed = false;
00665 if (constructor->IsHeapObject() &&
00666 !Heap::Contains(HeapObject::cast(constructor))) {
00667 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
00668 } else {
00669 bool global_object = IsJSGlobalProxy();
00670 if (constructor->IsJSFunction()) {
00671 if (!Heap::Contains(JSFunction::cast(constructor)->shared())) {
00672 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
00673 } else {
00674 Object* constructor_name =
00675 JSFunction::cast(constructor)->shared()->name();
00676 if (constructor_name->IsString()) {
00677 String* str = String::cast(constructor_name);
00678 if (str->length() > 0) {
00679 bool vowel = AnWord(str);
00680 accumulator->Add("<%sa%s ",
00681 global_object ? "Global Object: " : "",
00682 vowel ? "n" : "");
00683 accumulator->Put(str);
00684 accumulator->Put('>');
00685 printed = true;
00686 }
00687 }
00688 }
00689 }
00690 if (!printed) {
00691 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
00692 }
00693 }
00694 if (IsJSValue()) {
00695 accumulator->Add(" value = ");
00696 JSValue::cast(this)->value()->ShortPrint(accumulator);
00697 }
00698 accumulator->Put('>');
00699 break;
00700 }
00701 }
00702 }
00703
00704
00705 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
00706
00707 if (!Heap::Contains(this)) {
00708 accumulator->Add("!!!INVALID POINTER!!!");
00709 return;
00710 }
00711 if (!Heap::Contains(map())) {
00712 accumulator->Add("!!!INVALID MAP!!!");
00713 return;
00714 }
00715
00716 accumulator->Add("%p ", this);
00717
00718 if (IsString()) {
00719 String::cast(this)->StringShortPrint(accumulator);
00720 return;
00721 }
00722 if (IsJSObject()) {
00723 JSObject::cast(this)->JSObjectShortPrint(accumulator);
00724 return;
00725 }
00726 switch (map()->instance_type()) {
00727 case MAP_TYPE:
00728 accumulator->Add("<Map>");
00729 break;
00730 case FIXED_ARRAY_TYPE:
00731 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
00732 break;
00733 case BYTE_ARRAY_TYPE:
00734 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
00735 break;
00736 case SHARED_FUNCTION_INFO_TYPE:
00737 accumulator->Add("<SharedFunctionInfo>");
00738 break;
00739 #define MAKE_STRUCT_CASE(NAME, Name, name) \
00740 case NAME##_TYPE: \
00741 accumulator->Add(#Name); \
00742 break;
00743 STRUCT_LIST(MAKE_STRUCT_CASE)
00744 #undef MAKE_STRUCT_CASE
00745 case CODE_TYPE:
00746 accumulator->Add("<Code>");
00747 break;
00748 case ODDBALL_TYPE: {
00749 if (IsUndefined())
00750 accumulator->Add("<undefined>");
00751 else if (IsTheHole())
00752 accumulator->Add("<the hole>");
00753 else if (IsNull())
00754 accumulator->Add("<null>");
00755 else if (IsTrue())
00756 accumulator->Add("<true>");
00757 else if (IsFalse())
00758 accumulator->Add("<false>");
00759 else
00760 accumulator->Add("<Odd Oddball>");
00761 break;
00762 }
00763 case HEAP_NUMBER_TYPE:
00764 accumulator->Add("<Number: ");
00765 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
00766 accumulator->Put('>');
00767 break;
00768 case PROXY_TYPE:
00769 accumulator->Add("<Proxy>");
00770 break;
00771 default:
00772 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
00773 break;
00774 }
00775 }
00776
00777
00778 int HeapObject::SlowSizeFromMap(Map* map) {
00779
00780
00781 InstanceType instance_type = map->instance_type();
00782
00783 if (instance_type < FIRST_NONSTRING_TYPE
00784 && (reinterpret_cast<String*>(this)->map_representation_tag(map)
00785 == kSeqStringTag)) {
00786 if (reinterpret_cast<String*>(this)->is_ascii_representation_map(map)) {
00787 return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(map);
00788 } else {
00789 SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this);
00790 return self->SeqTwoByteStringSize(map);
00791 }
00792 }
00793
00794 switch (instance_type) {
00795 case FIXED_ARRAY_TYPE:
00796 return reinterpret_cast<FixedArray*>(this)->FixedArraySize();
00797 case BYTE_ARRAY_TYPE:
00798 return reinterpret_cast<ByteArray*>(this)->ByteArraySize();
00799 case CODE_TYPE:
00800 return reinterpret_cast<Code*>(this)->CodeSize();
00801 case MAP_TYPE:
00802 return Map::kSize;
00803 default:
00804 return map->instance_size();
00805 }
00806 }
00807
00808
00809 void HeapObject::Iterate(ObjectVisitor* v) {
00810
00811 IteratePointer(v, kMapOffset);
00812
00813 Map* m = map();
00814 IterateBody(m->instance_type(), SizeFromMap(m), v);
00815 }
00816
00817
00818 void HeapObject::IterateBody(InstanceType type, int object_size,
00819 ObjectVisitor* v) {
00820
00821
00822 if (type < FIRST_NONSTRING_TYPE) {
00823 switch (type & kStringRepresentationMask) {
00824 case kSeqStringTag:
00825 break;
00826 case kConsStringTag:
00827 reinterpret_cast<ConsString*>(this)->ConsStringIterateBody(v);
00828 break;
00829 case kSlicedStringTag:
00830 reinterpret_cast<SlicedString*>(this)->SlicedStringIterateBody(v);
00831 break;
00832 }
00833 return;
00834 }
00835
00836 switch (type) {
00837 case FIXED_ARRAY_TYPE:
00838 reinterpret_cast<FixedArray*>(this)->FixedArrayIterateBody(v);
00839 break;
00840 case JS_OBJECT_TYPE:
00841 case JS_VALUE_TYPE:
00842 case JS_ARRAY_TYPE:
00843 case JS_REGEXP_TYPE:
00844 case JS_FUNCTION_TYPE:
00845 case JS_GLOBAL_PROXY_TYPE:
00846 case JS_GLOBAL_OBJECT_TYPE:
00847 case JS_BUILTINS_OBJECT_TYPE:
00848 reinterpret_cast<JSObject*>(this)->JSObjectIterateBody(object_size, v);
00849 break;
00850 case ODDBALL_TYPE:
00851 reinterpret_cast<Oddball*>(this)->OddballIterateBody(v);
00852 break;
00853 case PROXY_TYPE:
00854 reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v);
00855 break;
00856 case MAP_TYPE:
00857 reinterpret_cast<Map*>(this)->MapIterateBody(v);
00858 break;
00859 case CODE_TYPE:
00860 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
00861 break;
00862 case HEAP_NUMBER_TYPE:
00863 case FILLER_TYPE:
00864 case BYTE_ARRAY_TYPE:
00865 break;
00866 case SHARED_FUNCTION_INFO_TYPE: {
00867 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
00868 shared->SharedFunctionInfoIterateBody(v);
00869 break;
00870 }
00871 #define MAKE_STRUCT_CASE(NAME, Name, name) \
00872 case NAME##_TYPE:
00873 STRUCT_LIST(MAKE_STRUCT_CASE)
00874 #undef MAKE_STRUCT_CASE
00875 IterateStructBody(object_size, v);
00876 break;
00877 default:
00878 PrintF("Unknown type: %d\n", type);
00879 UNREACHABLE();
00880 }
00881 }
00882
00883
00884 void HeapObject::IterateStructBody(int object_size, ObjectVisitor* v) {
00885 IteratePointers(v, HeapObject::kHeaderSize, object_size);
00886 }
00887
00888
00889 Object* HeapNumber::HeapNumberToBoolean() {
00890
00891 switch (fpclassify(value())) {
00892 case FP_NAN:
00893 case FP_ZERO: return Heap::false_value();
00894 default: return Heap::true_value();
00895 }
00896 }
00897
00898
00899 void HeapNumber::HeapNumberPrint() {
00900 PrintF("%.16g", Number());
00901 }
00902
00903
00904 void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
00905
00906
00907
00908
00909
00910
00911 EmbeddedVector<char, 100> buffer;
00912 OS::SNPrintF(buffer, "%.16g", Number());
00913 accumulator->Add("%s", buffer.start());
00914 }
00915
00916
00917 String* JSObject::class_name() {
00918 if (IsJSFunction()) return Heap::function_class_symbol();
00919 if (map()->constructor()->IsJSFunction()) {
00920 JSFunction* constructor = JSFunction::cast(map()->constructor());
00921 return String::cast(constructor->shared()->instance_class_name());
00922 }
00923
00924 return Heap::Object_symbol();
00925 }
00926
00927
00928 void JSObject::JSObjectIterateBody(int object_size, ObjectVisitor* v) {
00929
00930 IteratePointers(v, kPropertiesOffset, object_size);
00931 }
00932
00933
00934 Object* JSObject::AddFastPropertyUsingMap(Map* new_map,
00935 String* name,
00936 Object* value) {
00937 int index = new_map->PropertyIndexFor(name);
00938 if (map()->unused_property_fields() == 0) {
00939 ASSERT(map()->unused_property_fields() == 0);
00940 int new_unused = new_map->unused_property_fields();
00941 Object* values =
00942 properties()->CopySize(properties()->length() + new_unused + 1);
00943 if (values->IsFailure()) return values;
00944 set_properties(FixedArray::cast(values));
00945 }
00946 set_map(new_map);
00947 return FastPropertyAtPut(index, value);
00948 }
00949
00950
00951 Object* JSObject::AddFastProperty(String* name,
00952 Object* value,
00953 PropertyAttributes attributes) {
00954
00955 StringInputBuffer buffer(name);
00956 if (!Scanner::IsIdentifier(&buffer)) {
00957 Object* obj = NormalizeProperties();
00958 if (obj->IsFailure()) return obj;
00959 return AddSlowProperty(name, value, attributes);
00960 }
00961
00962 DescriptorArray* old_descriptors = map()->instance_descriptors();
00963
00964 int index = map()->NextFreePropertyIndex();
00965
00966
00967 FieldDescriptor new_field(name, index, attributes);
00968 Object* new_descriptors =
00969 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
00970 if (new_descriptors->IsFailure()) return new_descriptors;
00971
00972
00973
00974 bool allow_map_transition =
00975 !old_descriptors->Contains(name) &&
00976 (Top::context()->global_context()->object_function()->map() != map());
00977
00978 ASSERT(index < map()->inobject_properties() ||
00979 (index - map()->inobject_properties()) < properties()->length() ||
00980 map()->unused_property_fields() == 0);
00981
00982 Object* r = map()->Copy();
00983 if (r->IsFailure()) return r;
00984 Map* new_map = Map::cast(r);
00985 if (allow_map_transition) {
00986
00987 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
00988 Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
00989 if (r->IsFailure()) return r;
00990 old_descriptors = DescriptorArray::cast(r);
00991 }
00992
00993 if (map()->unused_property_fields() == 0) {
00994 if (properties()->length() > kMaxFastProperties) {
00995 Object* obj = NormalizeProperties();
00996 if (obj->IsFailure()) return obj;
00997 return AddSlowProperty(name, value, attributes);
00998 }
00999
01000 Object* values =
01001 properties()->CopySize(properties()->length() + kFieldsAdded);
01002 if (values->IsFailure()) return values;
01003 set_properties(FixedArray::cast(values));
01004 new_map->set_unused_property_fields(kFieldsAdded - 1);
01005 } else {
01006 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
01007 }
01008
01009
01010 map()->set_instance_descriptors(old_descriptors);
01011 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
01012 set_map(new_map);
01013 return FastPropertyAtPut(index, value);
01014 }
01015
01016
01017 Object* JSObject::AddConstantFunctionProperty(String* name,
01018 JSFunction* function,
01019 PropertyAttributes attributes) {
01020
01021 ConstantFunctionDescriptor d(name, function, attributes);
01022 Object* new_descriptors =
01023 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
01024 if (new_descriptors->IsFailure()) return new_descriptors;
01025
01026
01027 Object* new_map = map()->Copy();
01028 if (new_map->IsFailure()) return new_map;
01029
01030 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
01031 Map::cast(new_map)->set_instance_descriptors(descriptors);
01032 Map* old_map = map();
01033 set_map(Map::cast(new_map));
01034
01035
01036
01037 if (old_map == Top::context()->global_context()->object_function()->map()) {
01038 return function;
01039 }
01040
01041
01042 if (IsGlobalObject()) {
01043 return function;
01044 }
01045
01046
01047
01048
01049
01050 if (attributes != NONE) {
01051 return function;
01052 }
01053 ConstTransitionDescriptor mark(name);
01054 new_descriptors =
01055 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
01056 if (new_descriptors->IsFailure()) {
01057 return function;
01058 }
01059 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
01060
01061 return function;
01062 }
01063
01064
01065
01066 Object* JSObject::AddSlowProperty(String* name,
01067 Object* value,
01068 PropertyAttributes attributes) {
01069 PropertyDetails details = PropertyDetails(attributes, NORMAL);
01070 Object* result = property_dictionary()->AddStringEntry(name, value, details);
01071 if (result->IsFailure()) return result;
01072 if (property_dictionary() != result) {
01073 set_properties(Dictionary::cast(result));
01074 }
01075 return value;
01076 }
01077
01078
01079 Object* JSObject::AddProperty(String* name,
01080 Object* value,
01081 PropertyAttributes attributes) {
01082 ASSERT(!IsJSGlobalProxy());
01083 if (HasFastProperties()) {
01084
01085 if (map()->instance_descriptors()->number_of_descriptors() <
01086 DescriptorArray::kMaxNumberOfDescriptors) {
01087 if (value->IsJSFunction()) {
01088 return AddConstantFunctionProperty(name,
01089 JSFunction::cast(value),
01090 attributes);
01091 } else {
01092 return AddFastProperty(name, value, attributes);
01093 }
01094 } else {
01095
01096
01097 Object* obj = NormalizeProperties();
01098 if (obj->IsFailure()) return obj;
01099 }
01100 }
01101 return AddSlowProperty(name, value, attributes);
01102 }
01103
01104
01105 Object* JSObject::SetPropertyPostInterceptor(String* name,
01106 Object* value,
01107 PropertyAttributes attributes) {
01108
01109 LookupResult result;
01110 LocalLookupRealNamedProperty(name, &result);
01111 if (result.IsValid()) return SetProperty(&result, name, value, attributes);
01112
01113 return AddProperty(name, value, attributes);
01114 }
01115
01116
01117 Object* JSObject::ReplaceSlowProperty(String* name,
01118 Object* value,
01119 PropertyAttributes attributes) {
01120 Dictionary* dictionary = property_dictionary();
01121 PropertyDetails old_details =
01122 dictionary->DetailsAt(dictionary->FindStringEntry(name));
01123 int new_index = old_details.index();
01124 if (old_details.IsTransition()) new_index = 0;
01125
01126 PropertyDetails new_details(attributes, NORMAL, old_details.index());
01127 Object* result =
01128 property_dictionary()->SetOrAddStringEntry(name, value, new_details);
01129 if (result->IsFailure()) return result;
01130 if (property_dictionary() != result) {
01131 set_properties(Dictionary::cast(result));
01132 }
01133 return value;
01134 }
01135
01136 Object* JSObject::ConvertDescriptorToFieldAndMapTransition(
01137 String* name,
01138 Object* new_value,
01139 PropertyAttributes attributes) {
01140 Map* old_map = map();
01141 Object* result = ConvertDescriptorToField(name, new_value, attributes);
01142 if (result->IsFailure()) return result;
01143
01144
01145 if (!HasFastProperties()) {
01146 return result;
01147 }
01148
01149 if (map() == Top::context()->global_context()->object_function()->map()) {
01150 return result;
01151 }
01152
01153 MapTransitionDescriptor transition(name,
01154 map(),
01155 attributes);
01156 Object* new_descriptors =
01157 old_map->instance_descriptors()->
01158 CopyInsert(&transition, KEEP_TRANSITIONS);
01159 if (new_descriptors->IsFailure()) return result;
01160 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
01161 return result;
01162 }
01163
01164
01165 Object* JSObject::ConvertDescriptorToField(String* name,
01166 Object* new_value,
01167 PropertyAttributes attributes) {
01168 if (map()->unused_property_fields() == 0 &&
01169 properties()->length() > kMaxFastProperties) {
01170 Object* obj = NormalizeProperties();
01171 if (obj->IsFailure()) return obj;
01172 return ReplaceSlowProperty(name, new_value, attributes);
01173 }
01174
01175 int index = map()->NextFreePropertyIndex();
01176 FieldDescriptor new_field(name, index, attributes);
01177
01178 Object* descriptors_unchecked = map()->instance_descriptors()->
01179 CopyInsert(&new_field, REMOVE_TRANSITIONS);
01180 if (descriptors_unchecked->IsFailure()) return descriptors_unchecked;
01181 DescriptorArray* new_descriptors =
01182 DescriptorArray::cast(descriptors_unchecked);
01183
01184
01185 Object* new_map_unchecked = map()->Copy();
01186 if (new_map_unchecked->IsFailure()) return new_map_unchecked;
01187 Map* new_map = Map::cast(new_map_unchecked);
01188 new_map->set_instance_descriptors(new_descriptors);
01189
01190
01191 FixedArray* new_properties = 0;
01192 int new_unused_property_fields = map()->unused_property_fields() - 1;
01193 if (map()->unused_property_fields() == 0) {
01194 new_unused_property_fields = kFieldsAdded - 1;
01195 Object* new_properties_unchecked =
01196 properties()->CopySize(properties()->length() + kFieldsAdded);
01197 if (new_properties_unchecked->IsFailure()) return new_properties_unchecked;
01198 new_properties = FixedArray::cast(new_properties_unchecked);
01199 }
01200
01201
01202
01203 new_map->set_unused_property_fields(new_unused_property_fields);
01204 set_map(new_map);
01205 if (new_properties) {
01206 set_properties(FixedArray::cast(new_properties));
01207 }
01208 return FastPropertyAtPut(index, new_value);
01209 }
01210
01211
01212
01213 Object* JSObject::SetPropertyWithInterceptor(String* name,
01214 Object* value,
01215 PropertyAttributes attributes) {
01216 HandleScope scope;
01217 Handle<JSObject> this_handle(this);
01218 Handle<String> name_handle(name);
01219 Handle<Object> value_handle(value);
01220 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
01221 if (!interceptor->setter()->IsUndefined()) {
01222 Handle<Object> data_handle(interceptor->data());
01223 LOG(ApiNamedPropertyAccess("interceptor-named-set", this, name));
01224 v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
01225 v8::Utils::ToLocal(data_handle),
01226 v8::Utils::ToLocal(this_handle));
01227 v8::NamedPropertySetter setter =
01228 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
01229 v8::Handle<v8::Value> result;
01230 {
01231
01232 VMState state(OTHER);
01233 Handle<Object> value_unhole(value->IsTheHole() ?
01234 Heap::undefined_value() :
01235 value);
01236 result = setter(v8::Utils::ToLocal(name_handle),
01237 v8::Utils::ToLocal(value_unhole),
01238 info);
01239 }
01240 RETURN_IF_SCHEDULED_EXCEPTION();
01241 if (!result.IsEmpty()) return *value_handle;
01242 }
01243 Object* raw_result = this_handle->SetPropertyPostInterceptor(*name_handle,
01244 *value_handle,
01245 attributes);
01246 RETURN_IF_SCHEDULED_EXCEPTION();
01247 return raw_result;
01248 }
01249
01250
01251 Object* JSObject::SetProperty(String* name,
01252 Object* value,
01253 PropertyAttributes attributes) {
01254 LookupResult result;
01255 LocalLookup(name, &result);
01256 return SetProperty(&result, name, value, attributes);
01257 }
01258
01259
01260 Object* JSObject::SetPropertyWithCallback(Object* structure,
01261 String* name,
01262 Object* value,
01263 JSObject* holder) {
01264 HandleScope scope;
01265
01266
01267
01268 ASSERT(!value->IsTheHole());
01269 Handle<Object> value_handle(value);
01270
01271
01272
01273
01274 if (structure->IsProxy()) {
01275 AccessorDescriptor* callback =
01276 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
01277 Object* obj = (callback->setter)(this, value, callback->data);
01278 RETURN_IF_SCHEDULED_EXCEPTION();
01279 if (obj->IsFailure()) return obj;
01280 return *value_handle;
01281 }
01282
01283 if (structure->IsAccessorInfo()) {
01284
01285 AccessorInfo* data = AccessorInfo::cast(structure);
01286 Object* call_obj = data->setter();
01287 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
01288 if (call_fun == NULL) return value;
01289 Handle<JSObject> self(this);
01290 Handle<JSObject> holder_handle(JSObject::cast(holder));
01291 Handle<String> key(name);
01292 Handle<Object> fun_data(data->data());
01293 LOG(ApiNamedPropertyAccess("store", this, name));
01294 v8::AccessorInfo info(v8::Utils::ToLocal(self),
01295 v8::Utils::ToLocal(fun_data),
01296 v8::Utils::ToLocal(holder_handle));
01297 {
01298
01299 VMState state(OTHER);
01300 call_fun(v8::Utils::ToLocal(key),
01301 v8::Utils::ToLocal(value_handle),
01302 info);
01303 }
01304 RETURN_IF_SCHEDULED_EXCEPTION();
01305 return *value_handle;
01306 }
01307
01308 if (structure->IsFixedArray()) {
01309 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
01310 if (setter->IsJSFunction()) {
01311 Handle<JSFunction> fun(JSFunction::cast(setter));
01312 Handle<JSObject> self(this);
01313 bool has_pending_exception;
01314 Object** argv[] = { value_handle.location() };
01315 Execution::Call(fun, self, 1, argv, &has_pending_exception);
01316
01317 if (has_pending_exception) return Failure::Exception();
01318 } else {
01319 Handle<String> key(name);
01320 Handle<Object> holder_handle(holder);
01321 Handle<Object> args[2] = { key, holder_handle };
01322 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
01323 HandleVector(args, 2)));
01324 }
01325 return *value_handle;
01326 }
01327
01328 UNREACHABLE();
01329 return 0;
01330 }
01331
01332
01333 void JSObject::LookupCallbackSetterInPrototypes(String* name,
01334 LookupResult* result) {
01335 for (Object* pt = GetPrototype();
01336 pt != Heap::null_value();
01337 pt = pt->GetPrototype()) {
01338 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
01339 if (result->IsValid()) {
01340 if (!result->IsTransitionType() && result->IsReadOnly()) {
01341 result->NotFound();
01342 return;
01343 }
01344 if (result->type() == CALLBACKS) {
01345 return;
01346 }
01347 }
01348 }
01349 result->NotFound();
01350 }
01351
01352
01353 void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
01354 DescriptorArray* descriptors = map()->instance_descriptors();
01355 int number = descriptors->Search(name);
01356 if (number != DescriptorArray::kNotFound) {
01357 result->DescriptorResult(this, descriptors->GetDetails(number), number);
01358 } else {
01359 result->NotFound();
01360 }
01361 }
01362
01363
01364 void JSObject::LocalLookupRealNamedProperty(String* name,
01365 LookupResult* result) {
01366 if (IsJSGlobalProxy()) {
01367 Object* proto = GetPrototype();
01368 if (proto->IsNull()) return result->NotFound();
01369 ASSERT(proto->IsJSGlobalObject());
01370 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
01371 }
01372
01373 if (HasFastProperties()) {
01374 LookupInDescriptor(name, result);
01375 if (result->IsValid()) {
01376 ASSERT(result->holder() == this && result->type() != NORMAL);
01377
01378
01379 if (result->IsReadOnly() && result->type() == FIELD &&
01380 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
01381 result->DisallowCaching();
01382 }
01383 return;
01384 }
01385 } else {
01386 int entry = property_dictionary()->FindStringEntry(name);
01387 if (entry != DescriptorArray::kNotFound) {
01388
01389
01390 if (property_dictionary()->ValueAt(entry)->IsTheHole()) {
01391 result->DisallowCaching();
01392 }
01393 result->DictionaryResult(this, entry);
01394 return;
01395 }
01396
01397 result->DisallowCaching();
01398 }
01399 result->NotFound();
01400 }
01401
01402
01403 void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
01404 LocalLookupRealNamedProperty(name, result);
01405 if (result->IsProperty()) return;
01406
01407 LookupRealNamedPropertyInPrototypes(name, result);
01408 }
01409
01410
01411 void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
01412 LookupResult* result) {
01413 for (Object* pt = GetPrototype();
01414 pt != Heap::null_value();
01415 pt = JSObject::cast(pt)->GetPrototype()) {
01416 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
01417 if (result->IsValid()) {
01418 switch (result->type()) {
01419 case NORMAL:
01420 case FIELD:
01421 case CONSTANT_FUNCTION:
01422 case CALLBACKS:
01423 return;
01424 default: break;
01425 }
01426 }
01427 }
01428 result->NotFound();
01429 }
01430
01431
01432
01433 Object* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
01434 String* name,
01435 Object* value) {
01436 if (!result->IsProperty()) {
01437 LookupCallbackSetterInPrototypes(name, result);
01438 }
01439
01440 if (result->IsProperty()) {
01441 if (!result->IsReadOnly()) {
01442 switch (result->type()) {
01443 case CALLBACKS: {
01444 Object* obj = result->GetCallbackObject();
01445 if (obj->IsAccessorInfo()) {
01446 AccessorInfo* info = AccessorInfo::cast(obj);
01447 if (info->all_can_write()) {
01448 return SetPropertyWithCallback(result->GetCallbackObject(),
01449 name,
01450 value,
01451 result->holder());
01452 }
01453 }
01454 break;
01455 }
01456 case INTERCEPTOR: {
01457
01458
01459 LookupResult r;
01460 LookupRealNamedProperty(name, &r);
01461 if (r.IsProperty()) {
01462 return SetPropertyWithFailedAccessCheck(&r, name, value);
01463 }
01464 break;
01465 }
01466 default: {
01467 break;
01468 }
01469 }
01470 }
01471 }
01472
01473 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
01474 return value;
01475 }
01476
01477
01478 Object* JSObject::SetProperty(LookupResult* result,
01479 String* name,
01480 Object* value,
01481 PropertyAttributes attributes) {
01482
01483
01484 AssertNoContextChange ncc;
01485
01486
01487 if (IsAccessCheckNeeded()
01488 && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
01489 return SetPropertyWithFailedAccessCheck(result, name, value);
01490 }
01491
01492 if (IsJSGlobalProxy()) {
01493 Object* proto = GetPrototype();
01494 if (proto->IsNull()) return value;
01495 ASSERT(proto->IsJSGlobalObject());
01496 return JSObject::cast(proto)->SetProperty(result, name, value, attributes);
01497 }
01498
01499 if (result->IsNotFound() || !result->IsProperty()) {
01500
01501
01502 LookupResult accessor_result;
01503 LookupCallbackSetterInPrototypes(name, &accessor_result);
01504 if (accessor_result.IsValid()) {
01505 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
01506 name,
01507 value,
01508 accessor_result.holder());
01509 }
01510 }
01511 if (result->IsNotFound()) {
01512 return AddProperty(name, value, attributes);
01513 }
01514 if (!result->IsLoaded()) {
01515 return SetLazyProperty(result, name, value, attributes);
01516 }
01517 if (result->IsReadOnly() && result->IsProperty()) return value;
01518
01519
01520 switch (result->type()) {
01521 case NORMAL:
01522 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
01523 return value;
01524 case FIELD:
01525 return FastPropertyAtPut(result->GetFieldIndex(), value);
01526 case MAP_TRANSITION:
01527 if (attributes == result->GetAttributes()) {
01528
01529 return AddFastPropertyUsingMap(result->GetTransitionMap(),
01530 name,
01531 value);
01532 }
01533 return ConvertDescriptorToField(name, value, attributes);
01534 case CONSTANT_FUNCTION:
01535 if (value == result->GetConstantFunction()) return value;
01536
01537 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
01538 case CALLBACKS:
01539 return SetPropertyWithCallback(result->GetCallbackObject(),
01540 name,
01541 value,
01542 result->holder());
01543 case INTERCEPTOR:
01544 return SetPropertyWithInterceptor(name, value, attributes);
01545 case CONSTANT_TRANSITION:
01546
01547
01548 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
01549 case NULL_DESCRIPTOR:
01550 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
01551 default:
01552 UNREACHABLE();
01553 }
01554 UNREACHABLE();
01555 return value;
01556 }
01557
01558
01559
01560
01561
01562
01563
01564
01565 Object* JSObject::IgnoreAttributesAndSetLocalProperty(
01566 String* name,
01567 Object* value,
01568 PropertyAttributes attributes) {
01569
01570
01571 AssertNoContextChange ncc;
01572
01573 LookupResult result_struct;
01574 LocalLookup(name, &result_struct);
01575 LookupResult* result = &result_struct;
01576
01577
01578 if (IsAccessCheckNeeded()
01579 && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
01580 return SetPropertyWithFailedAccessCheck(result, name, value);
01581 }
01582
01583 if (result->IsNotFound()) {
01584 return AddProperty(name, value, attributes);
01585 }
01586 if (!result->IsLoaded()) {
01587 return SetLazyProperty(result, name, value, attributes);
01588 }
01589
01590 switch (result->type()) {
01591 case NORMAL:
01592 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
01593 return value;
01594 case FIELD:
01595 return FastPropertyAtPut(result->GetFieldIndex(), value);
01596 case MAP_TRANSITION:
01597 if (attributes == result->GetAttributes()) {
01598
01599 return AddFastPropertyUsingMap(result->GetTransitionMap(),
01600 name,
01601 value);
01602 } else {
01603 return ConvertDescriptorToField(name, value, attributes);
01604 }
01605 case CONSTANT_FUNCTION:
01606 if (value == result->GetConstantFunction()) return value;
01607
01608 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
01609 case CALLBACKS:
01610 return SetPropertyWithCallback(result->GetCallbackObject(),
01611 name,
01612 value,
01613 result->holder());
01614 case INTERCEPTOR:
01615 return SetPropertyWithInterceptor(name, value, attributes);
01616 case CONSTANT_TRANSITION:
01617
01618
01619 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
01620 case NULL_DESCRIPTOR:
01621 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
01622 default:
01623 UNREACHABLE();
01624 }
01625 UNREACHABLE();
01626 return value;
01627 }
01628
01629
01630 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
01631 JSObject* receiver,
01632 String* name,
01633 bool continue_search) {
01634
01635 LookupResult result;
01636 LocalLookupRealNamedProperty(name, &result);
01637 if (result.IsProperty()) return result.GetAttributes();
01638
01639 if (continue_search) {
01640
01641 Object* pt = GetPrototype();
01642 if (pt != Heap::null_value()) {
01643 return JSObject::cast(pt)->
01644 GetPropertyAttributeWithReceiver(receiver, name);
01645 }
01646 }
01647 return ABSENT;
01648 }
01649
01650
01651 PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
01652 JSObject* receiver,
01653 String* name,
01654 bool continue_search) {
01655
01656
01657 AssertNoContextChange ncc;
01658
01659 HandleScope scope;
01660 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
01661 Handle<JSObject> receiver_handle(receiver);
01662 Handle<JSObject> holder_handle(this);
01663 Handle<String> name_handle(name);
01664 Handle<Object> data_handle(interceptor->data());
01665 v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle),
01666 v8::Utils::ToLocal(data_handle),
01667 v8::Utils::ToLocal(holder_handle));
01668 if (!interceptor->query()->IsUndefined()) {
01669 v8::NamedPropertyQuery query =
01670 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
01671 LOG(ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
01672 v8::Handle<v8::Boolean> result;
01673 {
01674
01675 VMState state(OTHER);
01676 result = query(v8::Utils::ToLocal(name_handle), info);
01677 }
01678 if (!result.IsEmpty()) {
01679
01680
01681 return result->IsTrue() ? NONE : ABSENT;
01682 }
01683 } else if (!interceptor->getter()->IsUndefined()) {
01684 v8::NamedPropertyGetter getter =
01685 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
01686 LOG(ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
01687 v8::Handle<v8::Value> result;
01688 {
01689
01690 VMState state(OTHER);
01691 result = getter(v8::Utils::ToLocal(name_handle), info);
01692 }
01693 if (!result.IsEmpty()) return NONE;
01694 }
01695 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
01696 *name_handle,
01697 continue_search);
01698 }
01699
01700
01701 PropertyAttributes JSObject::GetPropertyAttributeWithReceiver(
01702 JSObject* receiver,
01703 String* key) {
01704 uint32_t index = 0;
01705 if (key->AsArrayIndex(&index)) {
01706 if (HasElementWithReceiver(receiver, index)) return NONE;
01707 return ABSENT;
01708 }
01709
01710 LookupResult result;
01711 Lookup(key, &result);
01712 return GetPropertyAttribute(receiver, &result, key, true);
01713 }
01714
01715
01716 PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
01717 LookupResult* result,
01718 String* name,
01719 bool continue_search) {
01720
01721 if (IsAccessCheckNeeded() &&
01722 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
01723 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
01724 return ABSENT;
01725 }
01726 if (result->IsValid()) {
01727 switch (result->type()) {
01728 case NORMAL:
01729 case FIELD:
01730 case CONSTANT_FUNCTION:
01731 case CALLBACKS:
01732 return result->GetAttributes();
01733 case INTERCEPTOR:
01734 return result->holder()->
01735 GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
01736 case MAP_TRANSITION:
01737 case CONSTANT_TRANSITION:
01738 case NULL_DESCRIPTOR:
01739 return ABSENT;
01740 default:
01741 UNREACHABLE();
01742 break;
01743 }
01744 }
01745 return ABSENT;
01746 }
01747
01748
01749 PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) {
01750
01751 uint32_t index = 0;
01752 if (name->AsArrayIndex(&index)) {
01753 if (HasLocalElement(index)) return NONE;
01754 return ABSENT;
01755 }
01756
01757 LookupResult result;
01758 LocalLookup(name, &result);
01759 return GetPropertyAttribute(this, &result, name, false);
01760 }
01761
01762
01763 Object* JSObject::NormalizeProperties() {
01764 if (!HasFastProperties()) return this;
01765
01766
01767 Object* obj =
01768 Dictionary::Allocate(map()->NumberOfDescribedProperties() * 2 + 4);
01769 if (obj->IsFailure()) return obj;
01770 Dictionary* dictionary = Dictionary::cast(obj);
01771
01772 for (DescriptorReader r(map()->instance_descriptors());
01773 !r.eos();
01774 r.advance()) {
01775 PropertyDetails details = r.GetDetails();
01776 switch (details.type()) {
01777 case CONSTANT_FUNCTION: {
01778 PropertyDetails d =
01779 PropertyDetails(details.attributes(), NORMAL, details.index());
01780 Object* value = r.GetConstantFunction();
01781 Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
01782 if (result->IsFailure()) return result;
01783 dictionary = Dictionary::cast(result);
01784 break;
01785 }
01786 case FIELD: {
01787 PropertyDetails d =
01788 PropertyDetails(details.attributes(), NORMAL, details.index());
01789 Object* value = FastPropertyAt(r.GetFieldIndex());
01790 Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
01791 if (result->IsFailure()) return result;
01792 dictionary = Dictionary::cast(result);
01793 break;
01794 }
01795 case CALLBACKS: {
01796 PropertyDetails d =
01797 PropertyDetails(details.attributes(), CALLBACKS, details.index());
01798 Object* value = r.GetCallbacksObject();
01799 Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
01800 if (result->IsFailure()) return result;
01801 dictionary = Dictionary::cast(result);
01802 break;
01803 }
01804 case MAP_TRANSITION:
01805 case CONSTANT_TRANSITION:
01806 case NULL_DESCRIPTOR:
01807 case INTERCEPTOR:
01808 break;
01809 default:
01810 case NORMAL:
01811 UNREACHABLE();
01812 break;
01813 }
01814 }
01815
01816
01817 int index = map()->instance_descriptors()->NextEnumerationIndex();
01818 dictionary->SetNextEnumerationIndex(index);
01819
01820
01821 obj = map()->Copy();
01822 if (obj->IsFailure()) return obj;
01823
01824
01825
01826 set_map(Map::cast(obj));
01827 map()->set_instance_descriptors(Heap::empty_descriptor_array());
01828
01829 map()->set_unused_property_fields(0);
01830 set_properties(dictionary);
01831
01832 Counters::props_to_dictionary.Increment();
01833
01834 #ifdef DEBUG
01835 if (FLAG_trace_normalization) {
01836 PrintF("Object properties have been normalized:\n");
01837 Print();
01838 }
01839 #endif
01840 return this;
01841 }
01842
01843
01844 Object* JSObject::TransformToFastProperties(int unused_property_fields) {
01845 if (HasFastProperties()) return this;
01846 return property_dictionary()->
01847 TransformPropertiesToFastFor(this, unused_property_fields);
01848 }
01849
01850
01851 Object* JSObject::NormalizeElements() {
01852 if (!HasFastElements()) return this;
01853
01854
01855 FixedArray* array = FixedArray::cast(elements());
01856
01857
01858 int length = IsJSArray() ?
01859 Smi::cast(JSArray::cast(this)->length())->value() :
01860 array->length();
01861 Object* obj = Dictionary::Allocate(length);
01862 if (obj->IsFailure()) return obj;
01863 Dictionary* dictionary = Dictionary::cast(obj);
01864
01865 for (int i = 0; i < length; i++) {
01866 Object* value = array->get(i);
01867 if (!value->IsTheHole()) {
01868 PropertyDetails details = PropertyDetails(NONE, NORMAL);
01869 Object* result = dictionary->AddNumberEntry(i, array->get(i), details);
01870 if (result->IsFailure()) return result;
01871 dictionary = Dictionary::cast(result);
01872 }
01873 }
01874
01875 set_elements(dictionary);
01876
01877 Counters::elements_to_dictionary.Increment();
01878
01879 #ifdef DEBUG
01880 if (FLAG_trace_normalization) {
01881 PrintF("Object elements have been normalized:\n");
01882 Print();
01883 }
01884 #endif
01885
01886 return this;
01887 }
01888
01889
01890 Object* JSObject::DeletePropertyPostInterceptor(String* name) {
01891
01892 LookupResult result;
01893 LocalLookupRealNamedProperty(name, &result);
01894 if (!result.IsValid()) return Heap::true_value();
01895
01896
01897 Object* obj = NormalizeProperties();
01898 if (obj->IsFailure()) return obj;
01899
01900 ASSERT(!HasFastProperties());
01901
01902 Dictionary* dictionary = property_dictionary();
01903 int entry = dictionary->FindStringEntry(name);
01904 if (entry != -1) return dictionary->DeleteProperty(entry);
01905 return Heap::true_value();
01906 }
01907
01908
01909 Object* JSObject::DeletePropertyWithInterceptor(String* name) {
01910 HandleScope scope;
01911 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
01912 Handle<String> name_handle(name);
01913 Handle<JSObject> this_handle(this);
01914 if (!interceptor->deleter()->IsUndefined()) {
01915 v8::NamedPropertyDeleter deleter =
01916 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
01917 Handle<Object> data_handle(interceptor->data());
01918 LOG(ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
01919 v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
01920 v8::Utils::ToLocal(data_handle),
01921 v8::Utils::ToLocal(this_handle));
01922 v8::Handle<v8::Boolean> result;
01923 {
01924
01925 VMState state(OTHER);
01926 result = deleter(v8::Utils::ToLocal(name_handle), info);
01927 }
01928 RETURN_IF_SCHEDULED_EXCEPTION();
01929 if (!result.IsEmpty()) {
01930 ASSERT(result->IsBoolean());
01931 return *v8::Utils::OpenHandle(*result);
01932 }
01933 }
01934 Object* raw_result = this_handle->DeletePropertyPostInterceptor(*name_handle);
01935 RETURN_IF_SCHEDULED_EXCEPTION();
01936 return raw_result;
01937 }
01938
01939
01940 Object* JSObject::DeleteElementPostInterceptor(uint32_t index) {
01941 if (HasFastElements()) {
01942 uint32_t length = IsJSArray() ?
01943 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
01944 static_cast<uint32_t>(FixedArray::cast(elements())->length());
01945 if (index < length) {
01946 FixedArray::cast(elements())->set_the_hole(index);
01947 }
01948 return Heap::true_value();
01949 }
01950 ASSERT(!HasFastElements());
01951 Dictionary* dictionary = element_dictionary();
01952 int entry = dictionary->FindNumberEntry(index);
01953 if (entry != -1) return dictionary->DeleteProperty(entry);
01954 return Heap::true_value();
01955 }
01956
01957
01958 Object* JSObject::DeleteElementWithInterceptor(uint32_t index) {
01959
01960
01961 AssertNoContextChange ncc;
01962 HandleScope scope;
01963 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
01964 if (interceptor->deleter()->IsUndefined()) return Heap::false_value();
01965 v8::IndexedPropertyDeleter deleter =
01966 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
01967 Handle<JSObject> this_handle(this);
01968 Handle<Object> data_handle(interceptor->data());
01969 LOG(ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
01970 v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
01971 v8::Utils::ToLocal(data_handle),
01972 v8::Utils::ToLocal(this_handle));
01973 v8::Handle<v8::Boolean> result;
01974 {
01975
01976 VMState state(OTHER);
01977 result = deleter(index, info);
01978 }
01979 RETURN_IF_SCHEDULED_EXCEPTION();
01980 if (!result.IsEmpty()) {
01981 ASSERT(result->IsBoolean());
01982 return *v8::Utils::OpenHandle(*result);
01983 }
01984 Object* raw_result = this_handle->DeleteElementPostInterceptor(index);
01985 RETURN_IF_SCHEDULED_EXCEPTION();
01986 return raw_result;
01987 }
01988
01989
01990 Object* JSObject::DeleteElement(uint32_t index) {
01991
01992 if (IsAccessCheckNeeded() &&
01993 !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
01994 Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
01995 return Heap::false_value();
01996 }
01997
01998 if (IsJSGlobalProxy()) {
01999 Object* proto = GetPrototype();
02000 if (proto->IsNull()) return Heap::false_value();
02001 ASSERT(proto->IsJSGlobalObject());
02002 return JSGlobalObject::cast(proto)->DeleteElement(index);
02003 }
02004
02005 if (HasIndexedInterceptor()) {
02006 return DeleteElementWithInterceptor(index);
02007 }
02008
02009 if (HasFastElements()) {
02010 uint32_t length = IsJSArray() ?
02011 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
02012 static_cast<uint32_t>(FixedArray::cast(elements())->length());
02013 if (index < length) {
02014 FixedArray::cast(elements())->set_the_hole(index);
02015 }
02016 return Heap::true_value();
02017 } else {
02018 Dictionary* dictionary = element_dictionary();
02019 int entry = dictionary->FindNumberEntry(index);
02020 if (entry != -1) return dictionary->DeleteProperty(entry);
02021 }
02022 return Heap::true_value();
02023 }
02024
02025
02026 Object* JSObject::DeleteProperty(String* name) {
02027
02028 ASSERT(name->IsString());
02029
02030
02031 if (IsAccessCheckNeeded() &&
02032 !Top::MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
02033 Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
02034 return Heap::false_value();
02035 }
02036
02037 if (IsJSGlobalProxy()) {
02038 Object* proto = GetPrototype();
02039 if (proto->IsNull()) return Heap::false_value();
02040 ASSERT(proto->IsJSGlobalObject());
02041 return JSGlobalObject::cast(proto)->DeleteProperty(name);
02042 }
02043
02044 uint32_t index = 0;
02045 if (name->AsArrayIndex(&index)) {
02046 return DeleteElement(index);
02047 } else {
02048 LookupResult result;
02049 LocalLookup(name, &result);
02050 if (!result.IsValid()) return Heap::true_value();
02051 if (result.IsDontDelete()) return Heap::false_value();
02052
02053 if (result.type() == INTERCEPTOR) {
02054 return DeletePropertyWithInterceptor(name);
02055 }
02056 if (!result.IsLoaded()) {
02057 return JSObject::cast(this)->DeleteLazyProperty(&result, name);
02058 }
02059
02060 Object* obj = NormalizeProperties();
02061 if (obj->IsFailure()) return obj;
02062
02063 Dictionary* dictionary = property_dictionary();
02064 int entry = dictionary->FindStringEntry(name);
02065 if (entry != -1) return dictionary->DeleteProperty(entry);
02066 return Heap::true_value();
02067 }
02068 }
02069
02070
02071
02072 bool JSObject::ReferencesObject(Object* obj) {
02073 AssertNoAllocation no_alloc;
02074
02075
02076 if (map()->constructor() == obj) {
02077 return true;
02078 }
02079
02080
02081 if (map()->prototype() == obj) {
02082 return true;
02083 }
02084
02085
02086 Object* key = SlowReverseLookup(obj);
02087 if (key != Heap::undefined_value()) {
02088 return true;
02089 }
02090
02091
02092 if (HasFastElements()) {
02093 int length = IsJSArray()
02094 ? Smi::cast(JSArray::cast(this)->length())->value()
02095 : FixedArray::cast(elements())->length();
02096 for (int i = 0; i < length; i++) {
02097 Object* element = FixedArray::cast(elements())->get(i);
02098 if (!element->IsTheHole() && element == obj) {
02099 return true;
02100 }
02101 }
02102 } else {
02103 key = element_dictionary()->SlowReverseLookup(obj);
02104 if (key != Heap::undefined_value()) {
02105 return true;
02106 }
02107 }
02108
02109
02110
02111 if (IsJSFunction() && !JSFunction::cast(this)->IsBoilerplate()) {
02112
02113 JSObject* arguments_boilerplate =
02114 Top::context()->global_context()->arguments_boilerplate();
02115 JSFunction* arguments_function =
02116 JSFunction::cast(arguments_boilerplate->map()->constructor());
02117
02118
02119 JSFunction* f = JSFunction::cast(this);
02120 Context* context = f->context();
02121 if (context->IsGlobalContext()) {
02122 return false;
02123 }
02124
02125
02126 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
02127
02128 if (context->get(i)->IsJSObject()) {
02129 JSObject* ctxobj = JSObject::cast(context->get(i));
02130
02131 if (ctxobj->map()->constructor() == arguments_function) {
02132 if (ctxobj->ReferencesObject(obj)) {
02133 return true;
02134 }
02135 } else if (ctxobj == obj) {
02136 return true;
02137 }
02138 }
02139 }
02140
02141
02142 if (context->has_extension()) {
02143 return context->extension()->ReferencesObject(obj);
02144 }
02145 }
02146
02147
02148 return false;
02149 }
02150
02151
02152
02153
02154
02155
02156
02157 bool JSObject::IsSimpleEnum() {
02158 JSObject* arguments_boilerplate =
02159 Top::context()->global_context()->arguments_boilerplate();
02160 JSFunction* arguments_function =
02161 JSFunction::cast(arguments_boilerplate->map()->constructor());
02162 if (IsAccessCheckNeeded()) return false;
02163 if (map()->constructor() == arguments_function) return false;
02164
02165 for (Object* o = this;
02166 o != Heap::null_value();
02167 o = JSObject::cast(o)->GetPrototype()) {
02168 JSObject* curr = JSObject::cast(o);
02169 if (!curr->HasFastProperties()) return false;
02170 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
02171 if (curr->NumberOfEnumElements() > 0) return false;
02172 if (curr->HasNamedInterceptor()) return false;
02173 if (curr->HasIndexedInterceptor()) return false;
02174 if (curr != this) {
02175 FixedArray* curr_fixed_array =
02176 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
02177 if (curr_fixed_array->length() > 0) {
02178 return false;
02179 }
02180 }
02181 }
02182 return true;
02183 }
02184
02185
02186 int Map::NumberOfDescribedProperties() {
02187 int result = 0;
02188 for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
02189 if (!r.IsTransition()) result++;
02190 }
02191 return result;
02192 }
02193
02194
02195 int Map::PropertyIndexFor(String* name) {
02196 for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
02197 if (r.Equals(name)) return r.GetFieldIndex();
02198 }
02199 return -1;
02200 }
02201
02202
02203 int Map::NextFreePropertyIndex() {
02204 int index = -1;
02205 for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
02206 if (r.type() == FIELD) {
02207 if (r.GetFieldIndex() > index) index = r.GetFieldIndex();
02208 }
02209 }
02210 return index+1;
02211 }
02212
02213
02214 AccessorDescriptor* Map::FindAccessor(String* name) {
02215 for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
02216 if (r.Equals(name) && r.type() == CALLBACKS) return r.GetCallbacks();
02217 }
02218 return NULL;
02219 }
02220
02221
02222 void JSObject::LocalLookup(String* name, LookupResult* result) {
02223 ASSERT(name->IsString());
02224
02225 if (IsJSGlobalProxy()) {
02226 Object* proto = GetPrototype();
02227 if (proto->IsNull()) return result->NotFound();
02228 ASSERT(proto->IsJSGlobalObject());
02229 return JSObject::cast(proto)->LocalLookup(name, result);
02230 }
02231
02232
02233
02234 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
02235 result->DisallowCaching();
02236 }
02237
02238
02239 if (name->Equals(Heap::Proto_symbol())) {
02240 result->ConstantResult(this);
02241 return;
02242 }
02243
02244
02245 if (HasNamedInterceptor() && !Bootstrapper::IsActive()) {
02246 result->InterceptorResult(this);
02247 return;
02248 }
02249
02250 LocalLookupRealNamedProperty(name, result);
02251 }
02252
02253
02254 void JSObject::Lookup(String* name, LookupResult* result) {
02255
02256 for (Object* current = this;
02257 current != Heap::null_value();
02258 current = JSObject::cast(current)->GetPrototype()) {
02259 JSObject::cast(current)->LocalLookup(name, result);
02260 if (result->IsValid() && !result->IsTransitionType()) {
02261 return;
02262 }
02263 }
02264 result->NotFound();
02265 }
02266
02267
02268 Object* JSObject::DefineGetterSetter(String* name,
02269 PropertyAttributes attributes) {
02270
02271
02272 AssertNoContextChange ncc;
02273
02274
02275 if (IsAccessCheckNeeded() &&
02276 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
02277 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
02278 return Heap::undefined_value();
02279 }
02280
02281
02282 name->TryFlatten();
02283
02284
02285 uint32_t index;
02286 if (name->AsArrayIndex(&index)) return Heap::undefined_value();
02287
02288
02289 LookupResult result;
02290 LocalLookup(name, &result);
02291 if (result.IsValid()) {
02292 if (result.IsReadOnly()) return Heap::undefined_value();
02293 if (result.type() == CALLBACKS) {
02294 Object* obj = result.GetCallbackObject();
02295 if (obj->IsFixedArray()) return obj;
02296 }
02297 }
02298
02299
02300 Object* ok = NormalizeProperties();
02301 if (ok->IsFailure()) return ok;
02302
02303
02304 Object* array = Heap::AllocateFixedArray(2);
02305 if (array->IsFailure()) return array;
02306
02307
02308 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
02309 Object* dict =
02310 property_dictionary()->SetOrAddStringEntry(name, array, details);
02311 if (dict->IsFailure()) return dict;
02312
02313
02314 set_properties(Dictionary::cast(dict));
02315 return array;
02316 }
02317
02318
02319 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun,
02320 PropertyAttributes attributes) {
02321
02322 if (IsAccessCheckNeeded() &&
02323 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
02324 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
02325 return Heap::undefined_value();
02326 }
02327
02328 if (IsJSGlobalProxy()) {
02329 Object* proto = GetPrototype();
02330 if (proto->IsNull()) return this;
02331 ASSERT(proto->IsJSGlobalObject());
02332 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
02333 fun, attributes);
02334 }
02335
02336 Object* array = DefineGetterSetter(name, attributes);
02337 if (array->IsFailure() || array->IsUndefined()) return array;
02338 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
02339 return this;
02340 }
02341
02342
02343 Object* JSObject::LookupAccessor(String* name, bool is_getter) {
02344
02345
02346 AssertNoContextChange ncc;
02347
02348
02349 if (IsAccessCheckNeeded() &&
02350 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
02351 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
02352 return Heap::undefined_value();
02353 }
02354
02355
02356 uint32_t index;
02357 if (name->AsArrayIndex(&index)) return Heap::undefined_value();
02358
02359
02360 for (Object* obj = this;
02361 obj != Heap::null_value();
02362 obj = JSObject::cast(obj)->GetPrototype()) {
02363 LookupResult result;
02364 JSObject::cast(obj)->LocalLookup(name, &result);
02365 if (result.IsValid()) {
02366 if (result.IsReadOnly()) return Heap::undefined_value();
02367 if (result.type() == CALLBACKS) {
02368 Object* obj = result.GetCallbackObject();
02369 if (obj->IsFixedArray()) {
02370 return FixedArray::cast(obj)->get(is_getter
02371 ? kGetterIndex
02372 : kSetterIndex);
02373 }
02374 }
02375 }
02376 }
02377 return Heap::undefined_value();
02378 }
02379
02380
02381 Object* JSObject::SlowReverseLookup(Object* value) {
02382 if (HasFastProperties()) {
02383 for (DescriptorReader r(map()->instance_descriptors());
02384 !r.eos();
02385 r.advance()) {
02386 if (r.type() == FIELD) {
02387 if (FastPropertyAt(r.GetFieldIndex()) == value) {
02388 return r.GetKey();
02389 }
02390 } else if (r.type() == CONSTANT_FUNCTION) {
02391 if (r.GetConstantFunction() == value) {
02392 return r.GetKey();
02393 }
02394 }
02395 }
02396 return Heap::undefined_value();
02397 } else {
02398 return property_dictionary()->SlowReverseLookup(value);
02399 }
02400 }
02401
02402
02403 Object* Map::Copy() {
02404 Object* result = Heap::AllocateMap(instance_type(), instance_size());
02405 if (result->IsFailure()) return result;
02406 Map::cast(result)->set_prototype(prototype());
02407 Map::cast(result)->set_constructor(constructor());
02408
02409 Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array());
02410
02411 Map::cast(result)->set_inobject_properties(inobject_properties());
02412 Map::cast(result)->set_unused_property_fields(unused_property_fields());
02413 Map::cast(result)->set_bit_field(bit_field());
02414 Map::cast(result)->ClearCodeCache();
02415 return result;
02416 }
02417
02418
02419 Object* Map::CopyDropTransitions() {
02420 Object* new_map = Copy();
02421 if (new_map->IsFailure()) return new_map;
02422 Object* descriptors = instance_descriptors()->RemoveTransitions();
02423 if (descriptors->IsFailure()) return descriptors;
02424 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
02425 return cast(new_map);
02426 }
02427
02428
02429 Object* Map::UpdateCodeCache(String* name, Code* code) {
02430 ASSERT(code->ic_state() == MONOMORPHIC);
02431 FixedArray* cache = code_cache();
02432
02433
02434
02435
02436 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
02437
02438
02439
02440 int length = cache->length();
02441 int deleted_index = -1;
02442 for (int i = 0; i < length; i += 2) {
02443 Object* key = cache->get(i);
02444 if (key->IsNull()) {
02445 if (deleted_index < 0) deleted_index = i;
02446 continue;
02447 }
02448 if (key->IsUndefined()) {
02449 if (deleted_index >= 0) i = deleted_index;
02450 cache->set(i + 0, name);
02451 cache->set(i + 1, code);
02452 return this;
02453 }
02454 if (name->Equals(String::cast(key))) {
02455 Code::Flags found = Code::cast(cache->get(i + 1))->flags();
02456 if (Code::RemoveTypeFromFlags(found) == flags) {
02457 cache->set(i + 1, code);
02458 return this;
02459 }
02460 }
02461 }
02462
02463
02464
02465 if (deleted_index >= 0) {
02466 cache->set(deleted_index + 0, name);
02467 cache->set(deleted_index + 1, code);
02468 return this;
02469 }
02470
02471
02472 int new_length = length + ((length >> 1) & ~1) + 2;
02473 ASSERT((new_length & 1) == 0);
02474 Object* result = cache->CopySize(new_length);
02475 if (result->IsFailure()) return result;
02476
02477
02478 cache = FixedArray::cast(result);
02479 cache->set(length + 0, name);
02480 cache->set(length + 1, code);
02481 set_code_cache(cache);
02482 return this;
02483 }
02484
02485
02486 Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
02487 FixedArray* cache = code_cache();
02488 int length = cache->length();
02489 for (int i = 0; i < length; i += 2) {
02490 Object* key = cache->get(i);
02491
02492 if (key->IsNull()) continue;
02493 if (key->IsUndefined()) return key;
02494 if (name->Equals(String::cast(key))) {
02495 Code* code = Code::cast(cache->get(i + 1));
02496 if (code->flags() == flags) return code;
02497 }
02498 }
02499 return Heap::undefined_value();
02500 }
02501
02502
02503 int Map::IndexInCodeCache(Code* code) {
02504 FixedArray* array = code_cache();
02505 int len = array->length();
02506 for (int i = 0; i < len; i += 2) {
02507 if (array->get(i + 1) == code) return i + 1;
02508 }
02509 return -1;
02510 }
02511
02512
02513 void Map::RemoveFromCodeCache(int index) {
02514 FixedArray* array = code_cache();
02515 ASSERT(array->length() >= index && array->get(index)->IsCode());
02516
02517
02518
02519 array->set_null(index - 1);
02520 array->set_null(index);
02521 }
02522
02523
02524 void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) {
02525 IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize);
02526 }
02527
02528
02529 static bool HasKey(FixedArray* array, Object* key) {
02530 int len0 = array->length();
02531 for (int i = 0; i < len0; i++) {
02532 Object* element = array->get(i);
02533 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
02534 if (element->IsString() &&
02535 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
02536 return true;
02537 }
02538 }
02539 return false;
02540 }
02541
02542
02543 Object* FixedArray::AddKeysFromJSArray(JSArray* array) {
02544
02545 Object* object = array->RemoveHoles();
02546 if (object->IsFailure()) return object;
02547 JSArray* compacted_array = JSArray::cast(object);
02548
02549
02550 int compacted_array_length = Smi::cast(compacted_array->length())->value();
02551 object = Heap::AllocateFixedArray(compacted_array_length);
02552 if (object->IsFailure()) return object;
02553 FixedArray* key_array = FixedArray::cast(object);
02554
02555
02556 for (int i = 0; i < compacted_array_length; i++) {
02557 key_array->set(i, compacted_array->GetElement(i));
02558 }
02559
02560
02561 return UnionOfKeys(key_array);
02562 }
02563
02564
02565 Object* FixedArray::UnionOfKeys(FixedArray* other) {
02566 int len0 = length();
02567 int len1 = other->length();
02568
02569 if (len0 == 0) return other;
02570 if (len1 == 0) return this;
02571
02572
02573 int extra = 0;
02574 for (int y = 0; y < len1; y++) {
02575 if (!HasKey(this, other->get(y))) extra++;
02576 }
02577
02578
02579 Object* obj = Heap::AllocateFixedArray(len0 + extra);
02580 if (obj->IsFailure()) return obj;
02581
02582 FixedArray* result = FixedArray::cast(obj);
02583 WriteBarrierMode mode = result->GetWriteBarrierMode();
02584 for (int i = 0; i < len0; i++) {
02585 result->set(i, get(i), mode);
02586 }
02587
02588 int index = 0;
02589 for (int y = 0; y < len1; y++) {
02590 if (!HasKey(this, other->get(y))) {
02591 result->set(len0 + index, other->get(y), mode);
02592 index++;
02593 }
02594 }
02595 ASSERT(extra == index);
02596 return result;
02597 }
02598
02599
02600 Object* FixedArray::CopySize(int new_length) {
02601 if (new_length == 0) return Heap::empty_fixed_array();
02602 Object* obj = Heap::AllocateFixedArray(new_length);
02603 if (obj->IsFailure()) return obj;
02604 FixedArray* result = FixedArray::cast(obj);
02605
02606 int len = length();
02607 if (new_length < len) len = new_length;
02608 result->set_map(map());
02609 WriteBarrierMode mode = result->GetWriteBarrierMode();
02610 for (int i = 0; i < len; i++) {
02611 result->set(i, get(i), mode);
02612 }
02613 return result;
02614 }
02615
02616
02617 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
02618 WriteBarrierMode mode = dest->GetWriteBarrierMode();
02619 for (int index = 0; index < len; index++) {
02620 dest->set(dest_pos+index, get(pos+index), mode);
02621 }
02622 }
02623
02624
02625 #ifdef DEBUG
02626 bool FixedArray::IsEqualTo(FixedArray* other) {
02627 if (length() != other->length()) return false;
02628 for (int i = 0 ; i < length(); ++i) {
02629 if (get(i) != other->get(i)) return false;
02630 }
02631 return true;
02632 }
02633 #endif
02634
02635
02636 Object* DescriptorArray::Allocate(int number_of_descriptors) {
02637 if (number_of_descriptors == 0) {
02638 return Heap::empty_descriptor_array();
02639 }
02640
02641 Object* array = Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors));
02642 if (array->IsFailure()) return array;
02643
02644 FixedArray* result = FixedArray::cast(array);
02645
02646
02647 array = Heap::AllocateFixedArray(number_of_descriptors << 1);
02648 if (array->IsFailure()) return array;
02649 result->set(kContentArrayIndex, array);
02650 result->set(kEnumerationIndexIndex,
02651 Smi::FromInt(PropertyDetails::kInitialIndex),
02652 SKIP_WRITE_BARRIER);
02653 return result;
02654 }
02655
02656
02657 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
02658 FixedArray* new_cache) {
02659 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
02660 if (HasEnumCache()) {
02661 FixedArray::cast(get(kEnumerationIndexIndex))->
02662 set(kEnumCacheBridgeCacheIndex, new_cache);
02663 } else {
02664 if (IsEmpty()) return;
02665 FixedArray::cast(bridge_storage)->
02666 set(kEnumCacheBridgeCacheIndex, new_cache);
02667 fast_set(FixedArray::cast(bridge_storage),
02668 kEnumCacheBridgeEnumIndex,
02669 get(kEnumerationIndexIndex));
02670 set(kEnumerationIndexIndex, bridge_storage);
02671 }
02672 }
02673
02674
02675 Object* DescriptorArray::CopyInsert(Descriptor* descriptor,
02676 TransitionFlag transition_flag) {
02677
02678
02679
02680
02681
02682 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
02683 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
02684 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
02685
02686
02687 Object* result = descriptor->KeyToSymbol();
02688 if (result->IsFailure()) return result;
02689
02690 int transitions = 0;
02691 int null_descriptors = 0;
02692 if (remove_transitions) {
02693 for (DescriptorReader r(this); !r.eos(); r.advance()) {
02694 if (r.IsTransition()) transitions++;
02695 if (r.IsNullDescriptor()) null_descriptors++;
02696 }
02697 } else {
02698 for (DescriptorReader r(this); !r.eos(); r.advance()) {
02699 if (r.IsNullDescriptor()) null_descriptors++;
02700 }
02701 }
02702 int new_size = number_of_descriptors() - transitions - null_descriptors;
02703
02704
02705 int index = Search(descriptor->GetKey());
02706 const bool inserting = (index == kNotFound);
02707 const bool replacing = !inserting;
02708 bool keep_enumeration_index = false;
02709 if (inserting) {
02710 ++new_size;
02711 }
02712 if (replacing) {
02713
02714
02715 PropertyType t = PropertyDetails(GetDetails(index)).type();
02716 if (t == CONSTANT_FUNCTION ||
02717 t == FIELD ||
02718 t == CALLBACKS ||
02719 t == INTERCEPTOR) {
02720 keep_enumeration_index = true;
02721 } else if (t == NULL_DESCRIPTOR || remove_transitions) {
02722
02723
02724 ++new_size;
02725 }
02726 }
02727 result = Allocate(new_size);
02728 if (result->IsFailure()) return result;
02729 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
02730
02731
02732 int enumeration_index = NextEnumerationIndex();
02733 if (!descriptor->GetDetails().IsTransition()) {
02734 if (keep_enumeration_index) {
02735 descriptor->SetEnumerationIndex(
02736 PropertyDetails(GetDetails(index)).index());
02737 } else {
02738 descriptor->SetEnumerationIndex(enumeration_index);
02739 ++enumeration_index;
02740 }
02741 }
02742 new_descriptors->SetNextEnumerationIndex(enumeration_index);
02743
02744
02745
02746 DescriptorWriter w(new_descriptors);
02747 DescriptorReader r(this);
02748 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
02749
02750 for (; !r.eos(); r.advance()) {
02751 if (r.GetKey()->Hash() > descriptor_hash ||
02752 r.GetKey() == descriptor->GetKey()) break;
02753 if (r.IsNullDescriptor()) continue;
02754 if (remove_transitions && r.IsTransition()) continue;
02755 w.WriteFrom(&r);
02756 }
02757 w.Write(descriptor);
02758 if (replacing) {
02759 ASSERT(r.GetKey() == descriptor->GetKey());
02760 r.advance();
02761 } else {
02762 ASSERT(r.eos() || r.GetKey()->Hash() > descriptor_hash);
02763 }
02764 for (; !r.eos(); r.advance()) {
02765 if (r.IsNullDescriptor()) continue;
02766 if (remove_transitions && r.IsTransition()) continue;
02767 w.WriteFrom(&r);
02768 }
02769 ASSERT(w.eos());
02770
02771 return new_descriptors;
02772 }
02773
02774
02775 Object* DescriptorArray::RemoveTransitions() {
02776
02777
02778
02779
02780 int count_transitions = 0;
02781 for (DescriptorReader r(this); !r.eos(); r.advance()) {
02782 if (r.IsTransition()) count_transitions++;
02783 }
02784
02785
02786 Object* result = Allocate(number_of_descriptors() - count_transitions);
02787 if (result->IsFailure()) return result;
02788 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
02789
02790
02791 DescriptorWriter w(new_descriptors);
02792 for (DescriptorReader r(this); !r.eos(); r.advance()) {
02793 if (!r.IsTransition()) w.WriteFrom(&r);
02794 }
02795 ASSERT(w.eos());
02796
02797 return new_descriptors;
02798 }
02799
02800
02801 void DescriptorArray::Sort() {
02802
02803 int len = number_of_descriptors();
02804
02805
02806 for (int i = 1; i < len; ++i) {
02807 int child_index = i;
02808 while (child_index > 0) {
02809 int parent_index = ((child_index + 1) >> 1) - 1;
02810 uint32_t parent_hash = GetKey(parent_index)->Hash();
02811 uint32_t child_hash = GetKey(child_index)->Hash();
02812 if (parent_hash < child_hash) {
02813 Swap(parent_index, child_index);
02814 } else {
02815 break;
02816 }
02817 child_index = parent_index;
02818 }
02819 }
02820
02821
02822 for (int i = len - 1; i > 0; --i) {
02823
02824 Swap(0, i);
02825
02826 int parent_index = 0;
02827 while (true) {
02828 int child_index = ((parent_index + 1) << 1) - 1;
02829 if (child_index >= i) break;
02830 uint32_t child1_hash = GetKey(child_index)->Hash();
02831 uint32_t child2_hash = GetKey(child_index + 1)->Hash();
02832 uint32_t parent_hash = GetKey(parent_index)->Hash();
02833 if (child_index + 1 >= i || child1_hash > child2_hash) {
02834 if (parent_hash > child1_hash) break;
02835 Swap(parent_index, child_index);
02836 parent_index = child_index;
02837 } else {
02838 if (parent_hash > child2_hash) break;
02839 Swap(parent_index, child_index + 1);
02840 parent_index = child_index + 1;
02841 }
02842 }
02843 }
02844
02845 SLOW_ASSERT(IsSortedNoDuplicates());
02846 }
02847
02848
02849 int DescriptorArray::BinarySearch(String* name, int low, int high) {
02850 uint32_t hash = name->Hash();
02851
02852 while (low <= high) {
02853 int mid = (low + high) / 2;
02854 String* mid_name = GetKey(mid);
02855 uint32_t mid_hash = mid_name->Hash();
02856
02857 if (mid_hash > hash) {
02858 high = mid - 1;
02859 continue;
02860 }
02861 if (mid_hash < hash) {
02862 low = mid + 1;
02863 continue;
02864 }
02865
02866 ASSERT(hash == mid_hash);
02867
02868
02869 if (name == mid_name) return mid;
02870 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
02871 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
02872 if (GetKey(mid)->Equals(name)) return mid;
02873 }
02874 break;
02875 }
02876 return kNotFound;
02877 }
02878
02879
02880 int DescriptorArray::LinearSearch(String* name, int len) {
02881 for (int number = 0; number < len; number++) {
02882 if (name->Equals(GetKey(number))) return number;
02883 }
02884 return kNotFound;
02885 }
02886
02887
02888 #ifdef DEBUG
02889 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
02890 if (IsEmpty()) return other->IsEmpty();
02891 if (other->IsEmpty()) return false;
02892 if (length() != other->length()) return false;
02893 for (int i = 0; i < length(); ++i) {
02894 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
02895 }
02896 return GetContentArray()->IsEqualTo(other->GetContentArray());
02897 }
02898 #endif
02899
02900
02901 static StaticResource<StringInputBuffer> string_input_buffer;
02902
02903
02904 bool String::LooksValid() {
02905 if (!Heap::Contains(this))
02906 return false;
02907 switch (representation_tag()) {
02908 case kSeqStringTag:
02909 case kConsStringTag:
02910 case kSlicedStringTag:
02911 case kExternalStringTag:
02912 return true;
02913 default:
02914 return false;
02915 }
02916 }
02917
02918
02919 int String::Utf8Length() {
02920 if (is_ascii_representation()) return length();
02921
02922
02923
02924
02925 TryFlatten();
02926 Access<StringInputBuffer> buffer(&string_input_buffer);
02927 buffer->Reset(0, this);
02928 int result = 0;
02929 while (buffer->has_more())
02930 result += unibrow::Utf8::Length(buffer->GetNext());
02931 return result;
02932 }
02933
02934
02935 Vector<const char> String::ToAsciiVector() {
02936 ASSERT(IsAsciiRepresentation());
02937 ASSERT(IsFlat());
02938
02939 int offset = 0;
02940 int length = this->length();
02941 StringRepresentationTag string_tag = representation_tag();
02942 String* string = this;
02943 if (string_tag == kSlicedStringTag) {
02944 SlicedString* sliced = SlicedString::cast(string);
02945 offset += sliced->start();
02946 string = String::cast(sliced->buffer());
02947 string_tag = string->representation_tag();
02948 } else if (string_tag == kConsStringTag) {
02949 ConsString* cons = ConsString::cast(string);
02950 ASSERT(String::cast(cons->second())->length() == 0);
02951 string = String::cast(cons->first());
02952 string_tag = string->representation_tag();
02953 }
02954 if (string_tag == kSeqStringTag) {
02955 SeqAsciiString* seq = SeqAsciiString::cast(string);
02956 char* start = seq->GetChars();
02957 return Vector<const char>(start + offset, length);
02958 }
02959 ASSERT(string_tag == kExternalStringTag);
02960 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
02961 const char* start = ext->resource()->data();
02962 return Vector<const char>(start + offset, length);
02963 }
02964
02965
02966 Vector<const uc16> String::ToUC16Vector() {
02967 ASSERT(IsTwoByteStringRepresentation());
02968 ASSERT(IsFlat());
02969
02970 int offset = 0;
02971 int length = this->length();
02972 StringRepresentationTag string_tag = representation_tag();
02973 String* string = this;
02974 if (string_tag == kSlicedStringTag) {
02975 SlicedString* sliced = SlicedString::cast(string);
02976 offset += sliced->start();
02977 string = String::cast(sliced->buffer());
02978 string_tag = string->representation_tag();
02979 } else if (string_tag == kConsStringTag) {
02980 ConsString* cons = ConsString::cast(string);
02981 ASSERT(String::cast(cons->second())->length() == 0);
02982 string = String::cast(cons->first());
02983 string_tag = string->representation_tag();
02984 }
02985 if (string_tag == kSeqStringTag) {
02986 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
02987 return Vector<const uc16>(seq->GetChars() + offset, length);
02988 }
02989 ASSERT(string_tag == kExternalStringTag);
02990 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
02991 const uc16* start =
02992 reinterpret_cast<const uc16*>(ext->resource()->data());
02993 return Vector<const uc16>(start + offset, length);
02994 }
02995
02996
02997 SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
02998 RobustnessFlag robust_flag,
02999 int offset,
03000 int length,
03001 int* length_return) {
03002 ASSERT(NativeAllocationChecker::allocation_allowed());
03003 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
03004 return SmartPointer<char>(NULL);
03005 }
03006
03007
03008 if (length < 0) length = kMaxInt - offset;
03009
03010
03011 Access<StringInputBuffer> buffer(&string_input_buffer);
03012 buffer->Reset(offset, this);
03013 int character_position = offset;
03014 int utf8_bytes = 0;
03015 while (buffer->has_more()) {
03016 uint16_t character = buffer->GetNext();
03017 if (character_position < offset + length) {
03018 utf8_bytes += unibrow::Utf8::Length(character);
03019 }
03020 character_position++;
03021 }
03022
03023 if (length_return) {
03024 *length_return = utf8_bytes;
03025 }
03026
03027 char* result = NewArray<char>(utf8_bytes + 1);
03028
03029
03030 buffer->Rewind();
03031 buffer->Seek(offset);
03032 character_position = offset;
03033 int utf8_byte_position = 0;
03034 while (buffer->has_more()) {
03035 uint16_t character = buffer->GetNext();
03036 if (character_position < offset + length) {
03037 if (allow_nulls == DISALLOW_NULLS && character == 0) {
03038 character = ' ';
03039 }
03040 utf8_byte_position +=
03041 unibrow::Utf8::Encode(result + utf8_byte_position, character);
03042 }
03043 character_position++;
03044 }
03045 result[utf8_byte_position] = 0;
03046 return SmartPointer<char>(result);
03047 }
03048
03049
03050 SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
03051 RobustnessFlag robust_flag,
03052 int* length_return) {
03053 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
03054 }
03055
03056
03057 const uc16* String::GetTwoByteData() {
03058 return GetTwoByteData(0);
03059 }
03060
03061
03062 const uc16* String::GetTwoByteData(unsigned start) {
03063 ASSERT(!IsAsciiRepresentation());
03064 switch (representation_tag()) {
03065 case kSeqStringTag:
03066 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
03067 case kExternalStringTag:
03068 return ExternalTwoByteString::cast(this)->
03069 ExternalTwoByteStringGetData(start);
03070 case kSlicedStringTag: {
03071 SlicedString* sliced_string = SlicedString::cast(this);
03072 String* buffer = String::cast(sliced_string->buffer());
03073 if (buffer->StringIsConsString()) {
03074 ConsString* cons_string = ConsString::cast(buffer);
03075
03076 ASSERT(String::cast(cons_string->second())->length() == 0);
03077 buffer = String::cast(cons_string->first());
03078 }
03079 return buffer->GetTwoByteData(start + sliced_string->start());
03080 }
03081 case kConsStringTag:
03082 UNREACHABLE();
03083 return NULL;
03084 }
03085 UNREACHABLE();
03086 return NULL;
03087 }
03088
03089
03090 SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
03091 ASSERT(NativeAllocationChecker::allocation_allowed());
03092
03093 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
03094 return SmartPointer<uc16>();
03095 }
03096
03097 Access<StringInputBuffer> buffer(&string_input_buffer);
03098 buffer->Reset(this);
03099
03100 uc16* result = NewArray<uc16>(length() + 1);
03101
03102 int i = 0;
03103 while (buffer->has_more()) {
03104 uint16_t character = buffer->GetNext();
03105 result[i++] = character;
03106 }
03107 result[i] = 0;
03108 return SmartPointer<uc16>(result);
03109 }
03110
03111
03112 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
03113 return reinterpret_cast<uc16*>(
03114 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
03115 }
03116
03117
03118 void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
03119 unsigned* offset_ptr,
03120 unsigned max_chars) {
03121 unsigned chars_read = 0;
03122 unsigned offset = *offset_ptr;
03123 while (chars_read < max_chars) {
03124 uint16_t c = *reinterpret_cast<uint16_t*>(
03125 reinterpret_cast<char*>(this) -
03126 kHeapObjectTag + kHeaderSize + offset * kShortSize);
03127 if (c <= kMaxAsciiCharCode) {
03128
03129 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
03130 rbb->util_buffer,
03131 rbb->capacity,
03132 rbb->cursor)) {
03133 break;
03134 }
03135 } else {
03136 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
03137 rbb->util_buffer,
03138 rbb->capacity,
03139 rbb->cursor)) {
03140 break;
03141 }
03142 }
03143 offset++;
03144 chars_read++;
03145 }
03146 *offset_ptr = offset;
03147 rbb->remaining += chars_read;
03148 }
03149
03150
03151 const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
03152 unsigned* remaining,
03153 unsigned* offset_ptr,
03154 unsigned max_chars) {
03155 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
03156 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
03157 *remaining = max_chars;
03158 *offset_ptr += max_chars;
03159 return b;
03160 }
03161
03162
03163
03164
03165
03166
03167
03168
03169
03170 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
03171 unsigned* offset_ptr,
03172 unsigned max_chars) {
03173 ConsString* current = this;
03174 unsigned offset = *offset_ptr;
03175 int offset_correction = 0;
03176
03177 while (true) {
03178 String* left = String::cast(current->first());
03179 unsigned left_length = (unsigned)left->length();
03180 if (left_length > offset &&
03181 (max_chars <= left_length - offset ||
03182 (rbb->capacity <= left_length - offset &&
03183 (max_chars = left_length - offset, true)))) {
03184
03185
03186
03187
03188
03189
03190
03191 if (left->StringIsConsString()) {
03192 current = ConsString::cast(left);
03193 continue;
03194 } else {
03195 const unibrow::byte* answer =
03196 String::ReadBlock(left, rbb, &offset, max_chars);
03197 *offset_ptr = offset + offset_correction;
03198 return answer;
03199 }
03200 } else if (left_length <= offset) {
03201
03202
03203 String* right = String::cast(current->second());
03204 offset -= left_length;
03205 offset_correction += left_length;
03206 if (right->StringIsConsString()) {
03207 current = ConsString::cast(right);
03208 continue;
03209 } else {
03210 const unibrow::byte* answer =
03211 String::ReadBlock(right, rbb, &offset, max_chars);
03212 *offset_ptr = offset + offset_correction;
03213 return answer;
03214 }
03215 } else {
03216
03217
03218
03219
03220
03221
03222 ASSERT(rbb->remaining == 0);
03223 ASSERT(rbb->cursor == 0);
03224 current->ConsStringReadBlockIntoBuffer(
03225 rbb,
03226 &offset,
03227 max_chars > rbb->capacity ? rbb->capacity : max_chars);
03228 *offset_ptr = offset + offset_correction;
03229 return rbb->util_buffer;
03230 }
03231 }
03232 }
03233
03234
03235 const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb,
03236 unsigned* offset_ptr,
03237 unsigned max_chars) {
03238 String* backing = String::cast(buffer());
03239 unsigned offset = start() + *offset_ptr;
03240 unsigned length = backing->length();
03241 if (max_chars > length - offset) {
03242 max_chars = length - offset;
03243 }
03244 const unibrow::byte* answer =
03245 String::ReadBlock(backing, rbb, &offset, max_chars);
03246 *offset_ptr = offset - start();
03247 return answer;
03248 }
03249
03250
03251 uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
03252 ASSERT(index >= 0 && index < length());
03253 return resource()->data()[index];
03254 }
03255
03256
03257 const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
03258 unsigned* remaining,
03259 unsigned* offset_ptr,
03260 unsigned max_chars) {
03261
03262 const unibrow::byte* b =
03263 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
03264 *remaining = max_chars;
03265 *offset_ptr += max_chars;
03266 return b;
03267 }
03268
03269
03270 const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
03271 unsigned start) {
03272 return resource()->data() + start;
03273 }
03274
03275
03276 uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
03277 ASSERT(index >= 0 && index < length());
03278 return resource()->data()[index];
03279 }
03280
03281
03282 void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
03283 ReadBlockBuffer* rbb,
03284 unsigned* offset_ptr,
03285 unsigned max_chars) {
03286 unsigned chars_read = 0;
03287 unsigned offset = *offset_ptr;
03288 const uint16_t* data = resource()->data();
03289 while (chars_read < max_chars) {
03290 uint16_t c = data[offset];
03291 if (c <= kMaxAsciiCharCode) {
03292
03293 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
03294 rbb->util_buffer,
03295 rbb->capacity,
03296 rbb->cursor))
03297 break;
03298 } else {
03299 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
03300 rbb->util_buffer,
03301 rbb->capacity,
03302 rbb->cursor))
03303 break;
03304 }
03305 offset++;
03306 chars_read++;
03307 }
03308 *offset_ptr = offset;
03309 rbb->remaining += chars_read;
03310 }
03311
03312
03313 void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
03314 unsigned* offset_ptr,
03315 unsigned max_chars) {
03316 unsigned capacity = rbb->capacity - rbb->cursor;
03317 if (max_chars > capacity) max_chars = capacity;
03318 memcpy(rbb->util_buffer + rbb->cursor,
03319 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
03320 *offset_ptr * kCharSize,
03321 max_chars);
03322 rbb->remaining += max_chars;
03323 *offset_ptr += max_chars;
03324 rbb->cursor += max_chars;
03325 }
03326
03327
03328 void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
03329 ReadBlockBuffer* rbb,
03330 unsigned* offset_ptr,
03331 unsigned max_chars) {
03332 unsigned capacity = rbb->capacity - rbb->cursor;
03333 if (max_chars > capacity) max_chars = capacity;
03334 memcpy(rbb->util_buffer + rbb->cursor,
03335 resource()->data() + *offset_ptr,
03336 max_chars);
03337 rbb->remaining += max_chars;
03338 *offset_ptr += max_chars;
03339 rbb->cursor += max_chars;
03340 }
03341
03342
03343
03344
03345
03346
03347 const unibrow::byte* String::ReadBlock(String* input,
03348 ReadBlockBuffer* rbb,
03349 unsigned* offset_ptr,
03350 unsigned max_chars) {
03351 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
03352 if (max_chars == 0) {
03353 rbb->remaining = 0;
03354 return NULL;
03355 }
03356 switch (input->representation_tag()) {
03357 case kSeqStringTag:
03358 if (input->is_ascii_representation()) {
03359 SeqAsciiString* str = SeqAsciiString::cast(input);
03360 return str->SeqAsciiStringReadBlock(&rbb->remaining,
03361 offset_ptr,
03362 max_chars);
03363 } else {
03364 SeqTwoByteString* str = SeqTwoByteString::cast(input);
03365 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
03366 offset_ptr,
03367 max_chars);
03368 return rbb->util_buffer;
03369 }
03370 case kConsStringTag:
03371 return ConsString::cast(input)->ConsStringReadBlock(rbb,
03372 offset_ptr,
03373 max_chars);
03374 case kSlicedStringTag:
03375 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
03376 offset_ptr,
03377 max_chars);
03378 case kExternalStringTag:
03379 if (input->is_ascii_representation()) {
03380 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
03381 &rbb->remaining,
03382 offset_ptr,
03383 max_chars);
03384 } else {
03385 ExternalTwoByteString::cast(input)->
03386 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
03387 offset_ptr,
03388 max_chars);
03389 return rbb->util_buffer;
03390 }
03391 default:
03392 break;
03393 }
03394
03395 UNREACHABLE();
03396 return 0;
03397 }
03398
03399
03400 void StringInputBuffer::Seek(unsigned pos) {
03401 Reset(pos, input_);
03402 }
03403
03404
03405 void SafeStringInputBuffer::Seek(unsigned pos) {
03406 Reset(pos, input_);
03407 }
03408
03409
03410
03411
03412
03413
03414 void String::ReadBlockIntoBuffer(String* input,
03415 ReadBlockBuffer* rbb,
03416 unsigned* offset_ptr,
03417 unsigned max_chars) {
03418 ASSERT(*offset_ptr <= (unsigned)input->length());
03419 if (max_chars == 0) return;
03420
03421 switch (input->representation_tag()) {
03422 case kSeqStringTag:
03423 if (input->is_ascii_representation()) {
03424 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
03425 offset_ptr,
03426 max_chars);
03427 return;
03428 } else {
03429 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
03430 offset_ptr,
03431 max_chars);
03432 return;
03433 }
03434 case kConsStringTag:
03435 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
03436 offset_ptr,
03437 max_chars);
03438 return;
03439 case kSlicedStringTag:
03440 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
03441 offset_ptr,
03442 max_chars);
03443 return;
03444 case kExternalStringTag:
03445 if (input->is_ascii_representation()) {
03446 ExternalAsciiString::cast(input)->
03447 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
03448 } else {
03449 ExternalTwoByteString::cast(input)->
03450 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
03451 offset_ptr,
03452 max_chars);
03453 }
03454 return;
03455 default:
03456 break;
03457 }
03458
03459 UNREACHABLE();
03460 return;
03461 }
03462
03463
03464 const unibrow::byte* String::ReadBlock(String* input,
03465 unibrow::byte* util_buffer,
03466 unsigned capacity,
03467 unsigned* remaining,
03468 unsigned* offset_ptr) {
03469 ASSERT(*offset_ptr <= (unsigned)input->length());
03470 unsigned chars = input->length() - *offset_ptr;
03471 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
03472 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
03473 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
03474 *remaining = rbb.remaining;
03475 return answer;
03476 }
03477
03478
03479 const unibrow::byte* String::ReadBlock(String** raw_input,
03480 unibrow::byte* util_buffer,
03481 unsigned capacity,
03482 unsigned* remaining,
03483 unsigned* offset_ptr) {
03484 Handle<String> input(raw_input);
03485 ASSERT(*offset_ptr <= (unsigned)input->length());
03486 unsigned chars = input->length() - *offset_ptr;
03487 if (chars > capacity) chars = capacity;
03488 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
03489 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
03490 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
03491 *remaining = rbb.remaining;
03492 return rbb.util_buffer;
03493 }
03494
03495
03496
03497
03498
03499
03500
03501 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
03502 unsigned* offset_ptr,
03503 unsigned max_chars) {
03504 ConsString* current = this;
03505 unsigned offset = *offset_ptr;
03506 int offset_correction = 0;
03507
03508 while (true) {
03509 String* left = String::cast(current->first());
03510 unsigned left_length = (unsigned)left->length();
03511 if (left_length > offset &&
03512 max_chars <= left_length - offset) {
03513
03514
03515 if (left->StringIsConsString()) {
03516 current = ConsString::cast(left);
03517 continue;
03518 } else {
03519 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
03520 *offset_ptr = offset + offset_correction;
03521 return;
03522 }
03523 } else if (left_length <= offset) {
03524
03525
03526 offset -= left_length;
03527 offset_correction += left_length;
03528 String* right = String::cast(current->second());
03529 if (right->StringIsConsString()) {
03530 current = ConsString::cast(right);
03531 continue;
03532 } else {
03533 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
03534 *offset_ptr = offset + offset_correction;
03535 return;
03536 }
03537 } else {
03538
03539
03540 max_chars -= left_length - offset;
03541 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
03542
03543
03544 if (offset == left_length) {
03545
03546 String* right = String::cast(current->second());
03547 offset -= left_length;
03548 offset_correction += left_length;
03549 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
03550 }
03551 *offset_ptr = offset + offset_correction;
03552 return;
03553 }
03554 }
03555 }
03556
03557
03558 void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
03559 unsigned* offset_ptr,
03560 unsigned max_chars) {
03561 String* backing = String::cast(buffer());
03562 unsigned offset = start() + *offset_ptr;
03563 unsigned length = backing->length();
03564 if (max_chars > length - offset) {
03565 max_chars = length - offset;
03566 }
03567 String::ReadBlockIntoBuffer(backing, rbb, &offset, max_chars);
03568 *offset_ptr = offset - start();
03569 }
03570
03571
03572 void ConsString::ConsStringIterateBody(ObjectVisitor* v) {
03573 IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize);
03574 }
03575
03576
03577 uint16_t ConsString::ConsStringGet(int index) {
03578 ASSERT(index >= 0 && index < this->length());
03579
03580
03581 if (String::cast(second())->length() == 0) {
03582 return String::cast(first())->Get(index);
03583 }
03584
03585 String* string = String::cast(this);
03586
03587 while (true) {
03588 if (string->StringIsConsString()) {
03589 ConsString* cons_string = ConsString::cast(string);
03590 String* left = String::cast(cons_string->first());
03591 if (left->length() > index) {
03592 string = left;
03593 } else {
03594 index -= left->length();
03595 string = String::cast(cons_string->second());
03596 }
03597 } else {
03598 return string->Get(index);
03599 }
03600 }
03601
03602 UNREACHABLE();
03603 return 0;
03604 }
03605
03606
03607 Object* SlicedString::SlicedStringFlatten() {
03608
03609
03610
03611 String* buf = String::cast(buffer());
03612 ASSERT(!buf->StringIsSlicedString());
03613 if (buf->StringIsConsString()) {
03614 Object* ok = buf->Flatten();
03615 if (ok->IsFailure()) return ok;
03616 }
03617 return this;
03618 }
03619
03620
03621 template <typename sinkchar>
03622 void String::WriteToFlat(String* src,
03623 sinkchar* sink,
03624 int f,
03625 int t) {
03626 String* source = src;
03627 int from = f;
03628 int to = t;
03629 while (true) {
03630 ASSERT(0 <= from && from <= to && to <= source->length());
03631 switch (source->full_representation_tag()) {
03632 case kAsciiStringTag | kExternalStringTag: {
03633 CopyChars(sink,
03634 ExternalAsciiString::cast(source)->resource()->data() + from,
03635 to - from);
03636 return;
03637 }
03638 case kTwoByteStringTag | kExternalStringTag: {
03639 const uc16* data =
03640 ExternalTwoByteString::cast(source)->resource()->data();
03641 CopyChars(sink,
03642 data + from,
03643 to - from);
03644 return;
03645 }
03646 case kAsciiStringTag | kSeqStringTag: {
03647 CopyChars(sink,
03648 SeqAsciiString::cast(source)->GetChars() + from,
03649 to - from);
03650 return;
03651 }
03652 case kTwoByteStringTag | kSeqStringTag: {
03653 CopyChars(sink,
03654 SeqTwoByteString::cast(source)->GetChars() + from,
03655 to - from);
03656 return;
03657 }
03658 case kAsciiStringTag | kSlicedStringTag:
03659 case kTwoByteStringTag | kSlicedStringTag: {
03660 SlicedString* sliced_string = SlicedString::cast(source);
03661 int start = sliced_string->start();
03662 from += start;
03663 to += start;
03664 source = String::cast(sliced_string->buffer());
03665 break;
03666 }
03667 case kAsciiStringTag | kConsStringTag:
03668 case kTwoByteStringTag | kConsStringTag: {
03669 ConsString* cons_string = ConsString::cast(source);
03670 String* first = String::cast(cons_string->first());
03671 int boundary = first->length();
03672 if (to - boundary >= boundary - from) {
03673
03674 if (from < boundary) {
03675 WriteToFlat(first, sink, from, boundary);
03676 sink += boundary - from;
03677 from = 0;
03678 } else {
03679 from -= boundary;
03680 }
03681 to -= boundary;
03682 source = String::cast(cons_string->second());
03683 } else {
03684
03685 if (to > boundary) {
03686 String* second = String::cast(cons_string->second());
03687 WriteToFlat(second,
03688 sink + boundary - from,
03689 0,
03690 to - boundary);
03691 to = boundary;
03692 }
03693 source = first;
03694 }
03695 break;
03696 }
03697 }
03698 }
03699 }
03700
03701
03702 void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) {
03703 IteratePointer(v, kBufferOffset);
03704 }
03705
03706
03707 uint16_t SlicedString::SlicedStringGet(int index) {
03708 ASSERT(index >= 0 && index < this->length());
03709
03710 return String::cast(buffer())->Get(start() + index);
03711 }
03712
03713
03714 template <typename IteratorA, typename IteratorB>
03715 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
03716
03717
03718 while (ia->has_more()) {
03719 uc32 ca = ia->GetNext();
03720 uc32 cb = ib->GetNext();
03721 if (ca != cb)
03722 return false;
03723 }
03724 return true;
03725 }
03726
03727
03728
03729
03730 template <typename Char>
03731 static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
03732 int length = a.length();
03733 ASSERT_EQ(length, b.length());
03734 const Char* pa = a.start();
03735 const Char* pb = b.start();
03736 int i = 0;
03737 #ifndef CAN_READ_UNALIGNED
03738
03739
03740
03741 const int kAlignmentMask = sizeof(uint32_t) - 1;
03742 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
03743 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
03744 if ((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask) == 0) {
03745 #endif
03746 const int kStepSize = sizeof(int) / sizeof(Char);
03747 int endpoint = length - kStepSize;
03748
03749 for (; i <= endpoint; i += kStepSize) {
03750 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
03751 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
03752 if (wa != wb) {
03753 return false;
03754 }
03755 }
03756 #ifndef CAN_READ_UNALIGNED
03757 }
03758 #endif
03759
03760 for (; i < length; i++) {
03761 if (a[i] != b[i]) {
03762 return false;
03763 }
03764 }
03765 return true;
03766 }
03767
03768
03769 static StringInputBuffer string_compare_buffer_b;
03770
03771
03772 template <typename IteratorA>
03773 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
03774 if (b->IsFlat()) {
03775 if (b->IsAsciiRepresentation()) {
03776 VectorIterator<char> ib(b->ToAsciiVector());
03777 return CompareStringContents(ia, &ib);
03778 } else {
03779 VectorIterator<uc16> ib(b->ToUC16Vector());
03780 return CompareStringContents(ia, &ib);
03781 }
03782 } else {
03783 string_compare_buffer_b.Reset(0, b);
03784 return CompareStringContents(ia, &string_compare_buffer_b);
03785 }
03786 }
03787
03788
03789 static StringInputBuffer string_compare_buffer_a;
03790
03791
03792 bool String::SlowEquals(String* other) {
03793
03794 int len = length();
03795 if (len != other->length()) return false;
03796 if (len == 0) return true;
03797
03798
03799
03800 if (HasHashCode() && other->HasHashCode()) {
03801 if (Hash() != other->Hash()) return false;
03802 }
03803
03804 if (this->IsSeqAsciiString() && other->IsSeqAsciiString()) {
03805 const char* str1 = SeqAsciiString::cast(this)->GetChars();
03806 const char* str2 = SeqAsciiString::cast(other)->GetChars();
03807 return CompareRawStringContents(Vector<const char>(str1, len),
03808 Vector<const char>(str2, len));
03809 }
03810
03811 if (this->IsFlat()) {
03812 if (this->IsAsciiRepresentation()) {
03813 Vector<const char> vec1 = this->ToAsciiVector();
03814 if (other->IsFlat()) {
03815 if (other->IsAsciiRepresentation()) {
03816 Vector<const char> vec2 = other->ToAsciiVector();
03817 return CompareRawStringContents(vec1, vec2);
03818 } else {
03819 VectorIterator<char> buf1(vec1);
03820 VectorIterator<uc16> ib(other->ToUC16Vector());
03821 return CompareStringContents(&buf1, &ib);
03822 }
03823 } else {
03824 VectorIterator<char> buf1(vec1);
03825 string_compare_buffer_b.Reset(0, other);
03826 return CompareStringContents(&buf1, &string_compare_buffer_b);
03827 }
03828 } else {
03829 Vector<const uc16> vec1 = this->ToUC16Vector();
03830 if (other->IsFlat()) {
03831 if (other->IsAsciiRepresentation()) {
03832 VectorIterator<uc16> buf1(vec1);
03833 VectorIterator<char> ib(other->ToAsciiVector());
03834 return CompareStringContents(&buf1, &ib);
03835 } else {
03836 Vector<const uc16> vec2(other->ToUC16Vector());
03837 return CompareRawStringContents(vec1, vec2);
03838 }
03839 } else {
03840 VectorIterator<uc16> buf1(vec1);
03841 string_compare_buffer_b.Reset(0, other);
03842 return CompareStringContents(&buf1, &string_compare_buffer_b);
03843 }
03844 }
03845 } else {
03846 string_compare_buffer_a.Reset(0, this);
03847 return CompareStringContentsPartial(&string_compare_buffer_a, other);
03848 }
03849 }
03850
03851
03852 bool String::MarkAsUndetectable() {
03853 if (this->IsSymbol()) return false;
03854
03855 Map* map = this->map();
03856 if (map == Heap::short_string_map()) {
03857 this->set_map(Heap::undetectable_short_string_map());
03858 return true;
03859 } else if (map == Heap::medium_string_map()) {
03860 this->set_map(Heap::undetectable_medium_string_map());
03861 return true;
03862 } else if (map == Heap::long_string_map()) {
03863 this->set_map(Heap::undetectable_long_string_map());
03864 return true;
03865 } else if (map == Heap::short_ascii_string_map()) {
03866 this->set_map(Heap::undetectable_short_ascii_string_map());
03867 return true;
03868 } else if (map == Heap::medium_ascii_string_map()) {
03869 this->set_map(Heap::undetectable_medium_ascii_string_map());
03870 return true;
03871 } else if (map == Heap::long_ascii_string_map()) {
03872 this->set_map(Heap::undetectable_long_ascii_string_map());
03873 return true;
03874 }
03875
03876 return false;
03877 }
03878
03879
03880 bool String::IsEqualTo(Vector<const char> str) {
03881 int slen = length();
03882 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
03883 decoder->Reset(str.start(), str.length());
03884 int i;
03885 for (i = 0; i < slen && decoder->has_more(); i++) {
03886 uc32 r = decoder->GetNext();
03887 if (Get(i) != r) return false;
03888 }
03889 return i == slen && !decoder->has_more();
03890 }
03891
03892
03893 uint32_t String::ComputeAndSetHash() {
03894
03895 ASSERT(!(length_field() & kHashComputedMask));
03896
03897
03898 StringInputBuffer buffer(this);
03899 uint32_t field = ComputeLengthAndHashField(&buffer, length());
03900
03901
03902 set_length_field(field);
03903
03904
03905 ASSERT(length_field() & kHashComputedMask);
03906 return field >> kHashShift;
03907 }
03908
03909
03910 bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
03911 uint32_t* index,
03912 int length) {
03913 if (length == 0 || length > kMaxArrayIndexSize) return false;
03914 uc32 ch = buffer->GetNext();
03915
03916
03917
03918 if (ch == '0') {
03919 *index = 0;
03920 return length == 1;
03921 }
03922
03923
03924 int d = ch - '0';
03925 if (d < 0 || d > 9) return false;
03926 uint32_t result = d;
03927 while (buffer->has_more()) {
03928 d = buffer->GetNext() - '0';
03929 if (d < 0 || d > 9) return false;
03930
03931 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
03932 result = (result * 10) + d;
03933 }
03934
03935 *index = result;
03936 return true;
03937 }
03938
03939
03940 bool String::SlowAsArrayIndex(uint32_t* index) {
03941 if (length() <= kMaxCachedArrayIndexLength) {
03942 Hash();
03943 uint32_t field = length_field();
03944 if ((field & kIsArrayIndexMask) == 0) return false;
03945 *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift;
03946 return true;
03947 } else {
03948 StringInputBuffer buffer(this);
03949 return ComputeArrayIndex(&buffer, index, length());
03950 }
03951 }
03952
03953
03954 static inline uint32_t HashField(uint32_t hash, bool is_array_index) {
03955 uint32_t result =
03956 (hash << String::kLongLengthShift) | String::kHashComputedMask;
03957 if (is_array_index) result |= String::kIsArrayIndexMask;
03958 return result;
03959 }
03960
03961
03962 uint32_t StringHasher::GetHashField() {
03963 ASSERT(is_valid());
03964 if (length_ <= String::kMaxShortStringSize) {
03965 uint32_t payload;
03966 if (is_array_index()) {
03967 payload = v8::internal::HashField(array_index(), true);
03968 } else {
03969 payload = v8::internal::HashField(GetHash(), false);
03970 }
03971 return (payload & ((1 << String::kShortLengthShift) - 1)) |
03972 (length_ << String::kShortLengthShift);
03973 } else if (length_ <= String::kMaxMediumStringSize) {
03974 uint32_t payload = v8::internal::HashField(GetHash(), false);
03975 return (payload & ((1 << String::kMediumLengthShift) - 1)) |
03976 (length_ << String::kMediumLengthShift);
03977 } else {
03978 return v8::internal::HashField(length_, false);
03979 }
03980 }
03981
03982
03983 uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
03984 int length) {
03985 StringHasher hasher(length);
03986
03987
03988
03989 if (hasher.has_trivial_hash()) {
03990 return hasher.GetHashField();
03991 }
03992
03993
03994
03995 while (buffer->has_more() && hasher.is_array_index()) {
03996 hasher.AddCharacter(buffer->GetNext());
03997 }
03998
03999
04000
04001 while (buffer->has_more()) {
04002 hasher.AddCharacterNoIndex(buffer->GetNext());
04003 }
04004
04005 return hasher.GetHashField();
04006 }
04007
04008
04009 Object* String::Slice(int start, int end) {
04010 if (start == 0 && end == length()) return this;
04011 int representation = representation_tag();
04012 if (representation == kSlicedStringTag) {
04013
04014
04015 SlicedString* str = SlicedString::cast(this);
04016 return Heap::AllocateSlicedString(String::cast(str->buffer()),
04017 str->start() + start,
04018 str->start() + end);
04019 }
04020 Object* answer = Heap::AllocateSlicedString(this, start, end);
04021 if (answer->IsFailure()) {
04022 return answer;
04023 }
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034 if (String::cast(answer)->StringIsSlicedString() &&
04035 representation == kConsStringTag) {
04036 TryFlatten();
04037
04038
04039 if (String::cast(ConsString::cast(this)->second())->length() == 0) {
04040 SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first());
04041 }
04042 }
04043 return answer;
04044 }
04045
04046
04047 void String::PrintOn(FILE* file) {
04048 int length = this->length();
04049 for (int i = 0; i < length; i++) {
04050 fprintf(file, "%c", Get(i));
04051 }
04052 }
04053
04054
04055 void Map::CreateBackPointers() {
04056 DescriptorArray* descriptors = instance_descriptors();
04057 for (DescriptorReader r(descriptors); !r.eos(); r.advance()) {
04058 if (r.type() == MAP_TRANSITION) {
04059
04060 Map* target = Map::cast(r.GetValue());
04061 #ifdef DEBUG
04062
04063 Object* source_prototype = prototype();
04064 Object* target_prototype = target->prototype();
04065 ASSERT(source_prototype->IsJSObject() ||
04066 source_prototype->IsMap() ||
04067 source_prototype->IsNull());
04068 ASSERT(target_prototype->IsJSObject() ||
04069 target_prototype->IsNull());
04070 ASSERT(source_prototype->IsMap() ||
04071 source_prototype == target_prototype);
04072 #endif
04073
04074
04075 *RawField(target, kPrototypeOffset) = this;
04076 }
04077 }
04078 }
04079
04080
04081 void Map::ClearNonLiveTransitions(Object* real_prototype) {
04082
04083
04084 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
04085 *RawField(this, Map::kInstanceDescriptorsOffset));
04086 if (d == Heap::empty_descriptor_array()) return;
04087 Smi* NullDescriptorDetails =
04088 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
04089 FixedArray* contents = reinterpret_cast<FixedArray*>(
04090 d->get(DescriptorArray::kContentArrayIndex));
04091 ASSERT(contents->length() >= 2);
04092 for (int i = 0; i < contents->length(); i += 2) {
04093
04094
04095
04096
04097
04098 PropertyDetails details(Smi::cast(contents->get(i + 1)));
04099 if (details.type() == MAP_TRANSITION) {
04100 Map* target = reinterpret_cast<Map*>(contents->get(i));
04101 ASSERT(target->IsHeapObject());
04102 if (!target->IsMarked()) {
04103 ASSERT(target->IsMap());
04104 contents->set(i + 1, NullDescriptorDetails, SKIP_WRITE_BARRIER);
04105 contents->set(i, Heap::null_value(), SKIP_WRITE_BARRIER);
04106 ASSERT(target->prototype() == this ||
04107 target->prototype() == real_prototype);
04108
04109 *RawField(target, Map::kPrototypeOffset) = real_prototype;
04110 }
04111 }
04112 }
04113 }
04114
04115
04116 void Map::MapIterateBody(ObjectVisitor* v) {
04117
04118 IteratePointers(v, kPrototypeOffset, kCodeCacheOffset + kPointerSize);
04119 }
04120
04121
04122 Object* JSFunction::SetInstancePrototype(Object* value) {
04123 ASSERT(value->IsJSObject());
04124
04125 if (has_initial_map()) {
04126 initial_map()->set_prototype(value);
04127 } else {
04128
04129
04130
04131 set_prototype_or_initial_map(value);
04132 }
04133 return value;
04134 }
04135
04136
04137
04138 Object* JSFunction::SetPrototype(Object* value) {
04139 Object* construct_prototype = value;
04140
04141
04142
04143
04144
04145 if (!value->IsJSObject()) {
04146
04147
04148
04149 Object* new_map = map()->CopyDropTransitions();
04150 if (new_map->IsFailure()) return new_map;
04151 set_map(Map::cast(new_map));
04152 map()->set_constructor(value);
04153 map()->set_non_instance_prototype(true);
04154 construct_prototype =
04155 Top::context()->global_context()->initial_object_prototype();
04156 } else {
04157 map()->set_non_instance_prototype(false);
04158 }
04159
04160 return SetInstancePrototype(construct_prototype);
04161 }
04162
04163
04164 Object* JSFunction::SetInstanceClassName(String* name) {
04165 shared()->set_instance_class_name(name);
04166 return this;
04167 }
04168
04169
04170 Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
04171 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
04172 }
04173
04174
04175 void Oddball::OddballIterateBody(ObjectVisitor* v) {
04176
04177 IteratePointers(v, kToStringOffset, kToNumberOffset + kPointerSize);
04178 }
04179
04180
04181 Object* Oddball::Initialize(const char* to_string, Object* to_number) {
04182 Object* symbol = Heap::LookupAsciiSymbol(to_string);
04183 if (symbol->IsFailure()) return symbol;
04184 set_to_string(String::cast(symbol));
04185 set_to_number(to_number);
04186 return this;
04187 }
04188
04189
04190 bool SharedFunctionInfo::HasSourceCode() {
04191 return !script()->IsUndefined() &&
04192 !Script::cast(script())->source()->IsUndefined();
04193 }
04194
04195
04196 Object* SharedFunctionInfo::GetSourceCode() {
04197 HandleScope scope;
04198 if (script()->IsUndefined()) return Heap::undefined_value();
04199 Object* source = Script::cast(script())->source();
04200 if (source->IsUndefined()) return Heap::undefined_value();
04201 return *SubString(Handle<String>(String::cast(source)),
04202 start_position(), end_position());
04203 }
04204
04205
04206
04207
04208 void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
04209 int max_length) {
04210
04211 if (script()->IsUndefined() ||
04212 Script::cast(script())->source()->IsUndefined()) {
04213 accumulator->Add("<No Source>");
04214 return;
04215 }
04216
04217
04218
04219
04220 String* script_source =
04221 reinterpret_cast<String*>(Script::cast(script())->source());
04222
04223 if (!script_source->LooksValid()) {
04224 accumulator->Add("<Invalid Source>");
04225 return;
04226 }
04227
04228 if (!is_toplevel()) {
04229 accumulator->Add("function ");
04230 Object* name = this->name();
04231 if (name->IsString() && String::cast(name)->length() > 0) {
04232 accumulator->PrintName(name);
04233 }
04234 }
04235
04236 int len = end_position() - start_position();
04237 if (len > max_length) {
04238 accumulator->Put(script_source,
04239 start_position(),
04240 start_position() + max_length);
04241 accumulator->Add("...\n");
04242 } else {
04243 accumulator->Put(script_source, start_position(), end_position());
04244 }
04245 }
04246
04247
04248 void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
04249 IteratePointers(v, kNameOffset, kCodeOffset + kPointerSize);
04250 IteratePointers(v, kInstanceClassNameOffset, kScriptOffset + kPointerSize);
04251 IteratePointer(v, kDebugInfoOffset);
04252 }
04253
04254
04255 void ObjectVisitor::BeginCodeIteration(Code* code) {
04256 ASSERT(code->ic_flag() == Code::IC_TARGET_IS_OBJECT);
04257 }
04258
04259
04260 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
04261 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
04262 VisitPointer(rinfo->target_object_address());
04263 }
04264
04265
04266 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
04267 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) && rinfo->is_call_instruction());
04268 VisitPointer(rinfo->call_object_address());
04269 }
04270
04271
04272
04273
04274
04275 void Code::ConvertICTargetsFromAddressToObject() {
04276 ASSERT(ic_flag() == IC_TARGET_IS_ADDRESS);
04277
04278 for (RelocIterator it(this, RelocInfo::kCodeTargetMask);
04279 !it.done(); it.next()) {
04280 Address ic_addr = it.rinfo()->target_address();
04281 ASSERT(ic_addr != NULL);
04282 HeapObject* code = HeapObject::FromAddress(ic_addr - Code::kHeaderSize);
04283 ASSERT(code->IsHeapObject());
04284 it.rinfo()->set_target_object(code);
04285 }
04286
04287 if (Debug::has_break_points()) {
04288 for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN));
04289 !it.done();
04290 it.next()) {
04291 if (it.rinfo()->is_call_instruction()) {
04292 Address addr = it.rinfo()->call_address();
04293 ASSERT(addr != NULL);
04294 HeapObject* code = HeapObject::FromAddress(addr - Code::kHeaderSize);
04295 ASSERT(code->IsHeapObject());
04296 it.rinfo()->set_call_object(code);
04297 }
04298 }
04299 }
04300 set_ic_flag(IC_TARGET_IS_OBJECT);
04301 }
04302
04303
04304 void Code::CodeIterateBody(ObjectVisitor* v) {
04305 v->BeginCodeIteration(this);
04306
04307 int mode_mask = RelocInfo::kCodeTargetMask |
04308 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
04309 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
04310 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
04311 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
04312
04313 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
04314 RelocInfo::Mode rmode = it.rinfo()->rmode();
04315 if (rmode == RelocInfo::EMBEDDED_OBJECT) {
04316 v->VisitPointer(it.rinfo()->target_object_address());
04317 } else if (RelocInfo::IsCodeTarget(rmode)) {
04318 v->VisitCodeTarget(it.rinfo());
04319 } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
04320 v->VisitExternalReference(it.rinfo()->target_reference_address());
04321 } else if (Debug::has_break_points() &&
04322 RelocInfo::IsJSReturn(rmode) &&
04323 it.rinfo()->is_call_instruction()) {
04324 v->VisitDebugTarget(it.rinfo());
04325 } else if (rmode == RelocInfo::RUNTIME_ENTRY) {
04326 v->VisitRuntimeEntry(it.rinfo());
04327 }
04328 }
04329
04330 ScopeInfo<>::IterateScopeInfo(this, v);
04331
04332 v->EndCodeIteration(this);
04333 }
04334
04335
04336 void Code::ConvertICTargetsFromObjectToAddress() {
04337 ASSERT(ic_flag() == IC_TARGET_IS_OBJECT);
04338
04339 for (RelocIterator it(this, RelocInfo::kCodeTargetMask);
04340 !it.done(); it.next()) {
04341
04342
04343
04344 Code* code = reinterpret_cast<Code*>(it.rinfo()->target_object());
04345 ASSERT((code != NULL) && code->IsHeapObject());
04346 it.rinfo()->set_target_address(code->instruction_start());
04347 }
04348
04349 if (Debug::has_break_points()) {
04350 for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN));
04351 !it.done();
04352 it.next()) {
04353 if (it.rinfo()->is_call_instruction()) {
04354 Code* code = reinterpret_cast<Code*>(it.rinfo()->call_object());
04355 ASSERT((code != NULL) && code->IsHeapObject());
04356 it.rinfo()->set_call_address(code->instruction_start());
04357 }
04358 }
04359 }
04360 set_ic_flag(IC_TARGET_IS_ADDRESS);
04361 }
04362
04363
04364 void Code::Relocate(int delta) {
04365 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
04366 it.rinfo()->apply(delta);
04367 }
04368 CPU::FlushICache(instruction_start(), instruction_size());
04369 }
04370
04371
04372 void Code::CopyFrom(const CodeDesc& desc) {
04373
04374 memmove(instruction_start(), desc.buffer, desc.instr_size);
04375
04376
04377 { byte* p = instruction_start() + desc.instr_size;
04378 byte* q = relocation_start();
04379 while (p < q) {
04380 *p++ = 0;
04381 }
04382 }
04383
04384
04385 memmove(relocation_start(),
04386 desc.buffer + desc.buffer_size - desc.reloc_size,
04387 desc.reloc_size);
04388
04389
04390 int delta = instruction_start() - desc.buffer;
04391 int mode_mask = RelocInfo::kCodeTargetMask |
04392 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
04393 RelocInfo::kApplyMask;
04394 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
04395 RelocInfo::Mode mode = it.rinfo()->rmode();
04396 if (mode == RelocInfo::EMBEDDED_OBJECT) {
04397 Object** p = reinterpret_cast<Object**>(it.rinfo()->target_object());
04398 it.rinfo()->set_target_object(*p);
04399 } else if (RelocInfo::IsCodeTarget(mode)) {
04400
04401
04402 Object** p = reinterpret_cast<Object**>(it.rinfo()->target_object());
04403 Code* code = Code::cast(*p);
04404 it.rinfo()->set_target_address(code->instruction_start());
04405 } else {
04406 it.rinfo()->apply(delta);
04407 }
04408 }
04409 CPU::FlushICache(instruction_start(), instruction_size());
04410 }
04411
04412
04413
04414
04415
04416
04417 int Code::SourcePosition(Address pc) {
04418 int distance = kMaxInt;
04419 int position = RelocInfo::kNoPosition;
04420
04421
04422
04423
04424 RelocIterator it(this, RelocInfo::kPositionMask);
04425 while (!it.done()) {
04426
04427 if (it.rinfo()->pc() < pc) {
04428
04429 int dist = pc - it.rinfo()->pc();
04430 int pos = it.rinfo()->data();
04431
04432
04433
04434 if ((dist < distance) ||
04435 (dist == distance && pos > position)) {
04436 position = pos;
04437 distance = dist;
04438 }
04439 }
04440 it.next();
04441 }
04442 return position;
04443 }
04444
04445
04446
04447
04448 int Code::SourceStatementPosition(Address pc) {
04449
04450
04451 int position = SourcePosition(pc);
04452
04453 int statement_position = 0;
04454 RelocIterator it(this, RelocInfo::kPositionMask);
04455 while (!it.done()) {
04456 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
04457 int p = it.rinfo()->data();
04458 if (statement_position < p && p <= position) {
04459 statement_position = p;
04460 }
04461 }
04462 it.next();
04463 }
04464 return statement_position;
04465 }
04466
04467
04468 #ifdef ENABLE_DISASSEMBLER
04469
04470 const char* Code::Kind2String(Kind kind) {
04471 switch (kind) {
04472 case FUNCTION: return "FUNCTION";
04473 case STUB: return "STUB";
04474 case BUILTIN: return "BUILTIN";
04475 case LOAD_IC: return "LOAD_IC";
04476 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
04477 case STORE_IC: return "STORE_IC";
04478 case KEYED_STORE_IC: return "KEYED_STORE_IC";
04479 case CALL_IC: return "CALL_IC";
04480 }
04481 UNREACHABLE();
04482 return NULL;
04483 }
04484
04485
04486 const char* Code::ICState2String(InlineCacheState state) {
04487 switch (state) {
04488 case UNINITIALIZED: return "UNINITIALIZED";
04489 case PREMONOMORPHIC: return "PREMONOMORPHIC";
04490 case MONOMORPHIC: return "MONOMORPHIC";
04491 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
04492 case MEGAMORPHIC: return "MEGAMORPHIC";
04493 case DEBUG_BREAK: return "DEBUG_BREAK";
04494 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
04495 }
04496 UNREACHABLE();
04497 return NULL;
04498 }
04499
04500
04501 void Code::Disassemble() {
04502 PrintF("kind = %s", Kind2String(kind()));
04503
04504 PrintF("\nInstructions (size = %d)\n", instruction_size());
04505 Disassembler::Decode(NULL, this);
04506 PrintF("\n");
04507
04508 PrintF("RelocInfo (size = %d)\n", relocation_size());
04509 for (RelocIterator it(this); !it.done(); it.next())
04510 it.rinfo()->Print();
04511 PrintF("\n");
04512 }
04513 #endif // ENABLE_DISASSEMBLER
04514
04515
04516 void JSObject::SetFastElements(FixedArray* elems) {
04517 #ifdef DEBUG
04518
04519 uint32_t len = static_cast<uint32_t>(elems->length());
04520 for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole());
04521 #endif
04522 WriteBarrierMode mode = elems->GetWriteBarrierMode();
04523 if (HasFastElements()) {
04524 FixedArray* old_elements = FixedArray::cast(elements());
04525 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
04526
04527 for (uint32_t i = 0; i < old_length; i++) {
04528 elems->set(i, old_elements->get(i), mode);
04529 }
04530 } else {
04531 Dictionary* dictionary = Dictionary::cast(elements());
04532 for (int i = 0; i < dictionary->Capacity(); i++) {
04533 Object* key = dictionary->KeyAt(i);
04534 if (key->IsNumber()) {
04535 uint32_t entry = static_cast<uint32_t>(key->Number());
04536 elems->set(entry, dictionary->ValueAt(i), mode);
04537 }
04538 }
04539 }
04540 set_elements(elems);
04541 }
04542
04543
04544 Object* JSObject::SetSlowElements(Object* len) {
04545 uint32_t new_length = static_cast<uint32_t>(len->Number());
04546
04547 if (!HasFastElements()) {
04548 if (IsJSArray()) {
04549 uint32_t old_length =
04550 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
04551 element_dictionary()->RemoveNumberEntries(new_length, old_length),
04552 JSArray::cast(this)->set_length(len);
04553 }
04554 return this;
04555 }
04556
04557
04558 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
04559 new_length);
04560 Object* obj = NormalizeElements();
04561 if (obj->IsFailure()) return obj;
04562
04563
04564 if (IsJSArray()) JSArray::cast(this)->set_length(len);
04565 return this;
04566 }
04567
04568
04569 Object* JSArray::Initialize(int capacity) {
04570 ASSERT(capacity >= 0);
04571 set_length(Smi::FromInt(0), SKIP_WRITE_BARRIER);
04572 FixedArray* new_elements;
04573 if (capacity == 0) {
04574 new_elements = Heap::empty_fixed_array();
04575 } else {
04576 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
04577 if (obj->IsFailure()) return obj;
04578 new_elements = FixedArray::cast(obj);
04579 }
04580 set_elements(new_elements);
04581 return this;
04582 }
04583
04584
04585
04586 static int NewElementsCapacity(int old_capacity) {
04587
04588 return old_capacity + (old_capacity >> 1) + 16;
04589 }
04590
04591
04592 static Object* ArrayLengthRangeError() {
04593 HandleScope scope;
04594 return Top::Throw(*Factory::NewRangeError("invalid_array_length",
04595 HandleVector<Object>(NULL, 0)));
04596 }
04597
04598
04599 Object* JSObject::SetElementsLength(Object* len) {
04600 Object* smi_length = len->ToSmi();
04601 if (smi_length->IsSmi()) {
04602 int value = Smi::cast(smi_length)->value();
04603 if (value < 0) return ArrayLengthRangeError();
04604 if (HasFastElements()) {
04605 int old_capacity = FixedArray::cast(elements())->length();
04606 if (value <= old_capacity) {
04607 if (IsJSArray()) {
04608 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
04609
04610
04611
04612 for (int i = value; i < old_length; i++) {
04613 FixedArray::cast(elements())->set_the_hole(i);
04614 }
04615 JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER);
04616 }
04617 return this;
04618 }
04619 int min = NewElementsCapacity(old_capacity);
04620 int new_capacity = value > min ? value : min;
04621 if (new_capacity <= kMaxFastElementsLength ||
04622 !ShouldConvertToSlowElements(new_capacity)) {
04623 Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
04624 if (obj->IsFailure()) return obj;
04625 if (IsJSArray()) JSArray::cast(this)->set_length(smi_length,
04626 SKIP_WRITE_BARRIER);
04627 SetFastElements(FixedArray::cast(obj));
04628 return this;
04629 }
04630 } else {
04631 if (IsJSArray()) {
04632 if (value == 0) {
04633
04634
04635
04636 initialize_elements();
04637 } else {
04638
04639 uint32_t old_length =
04640 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
04641 element_dictionary()->RemoveNumberEntries(value, old_length);
04642 }
04643 JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER);
04644 }
04645 return this;
04646 }
04647 }
04648
04649
04650 if (len->IsNumber()) {
04651 uint32_t length;
04652 if (Array::IndexFromObject(len, &length)) {
04653 return SetSlowElements(len);
04654 } else {
04655 return ArrayLengthRangeError();
04656 }
04657 }
04658
04659
04660
04661 Object* obj = Heap::AllocateFixedArray(1);
04662 if (obj->IsFailure()) return obj;
04663 FixedArray::cast(obj)->set(0, len);
04664 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1),
04665 SKIP_WRITE_BARRIER);
04666 set_elements(FixedArray::cast(obj));
04667 return this;
04668 }
04669
04670
04671 bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
04672 if (HasFastElements()) {
04673 uint32_t length = IsJSArray() ?
04674 static_cast<uint32_t>(
04675 Smi::cast(JSArray::cast(this)->length())->value()) :
04676 static_cast<uint32_t>(FixedArray::cast(elements())->length());
04677 if ((index < length) &&
04678 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
04679 return true;
04680 }
04681 } else {
04682 if (element_dictionary()->FindNumberEntry(index) != -1) return true;
04683 }
04684
04685
04686 if (this->IsStringObjectWithCharacterAt(index)) return true;
04687
04688 Object* pt = GetPrototype();
04689 if (pt == Heap::null_value()) return false;
04690 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
04691 }
04692
04693
04694 bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
04695
04696
04697 AssertNoContextChange ncc;
04698 HandleScope scope;
04699 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
04700 Handle<JSObject> receiver_handle(receiver);
04701 Handle<JSObject> holder_handle(this);
04702 Handle<Object> data_handle(interceptor->data());
04703 v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle),
04704 v8::Utils::ToLocal(data_handle),
04705 v8::Utils::ToLocal(holder_handle));
04706 if (!interceptor->query()->IsUndefined()) {
04707 v8::IndexedPropertyQuery query =
04708 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
04709 LOG(ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
04710 v8::Handle<v8::Boolean> result;
04711 {
04712
04713 VMState state(OTHER);
04714 result = query(index, info);
04715 }
04716 if (!result.IsEmpty()) return result->IsTrue();
04717 } else if (!interceptor->getter()->IsUndefined()) {
04718 v8::IndexedPropertyGetter getter =
04719 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
04720 LOG(ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
04721 v8::Handle<v8::Value> result;
04722 {
04723
04724 VMState state(OTHER);
04725 result = getter(index, info);
04726 }
04727 if (!result.IsEmpty()) return !result->IsUndefined();
04728 }
04729 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
04730 }
04731
04732
04733 bool JSObject::HasLocalElement(uint32_t index) {
04734
04735 if (IsAccessCheckNeeded() &&
04736 !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
04737 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
04738 return false;
04739 }
04740
04741
04742 if (HasIndexedInterceptor()) {
04743 return HasElementWithInterceptor(this, index);
04744 }
04745
04746
04747 if (this->IsStringObjectWithCharacterAt(index)) return true;
04748
04749 if (HasFastElements()) {
04750 uint32_t length = IsJSArray() ?
04751 static_cast<uint32_t>(
04752 Smi::cast(JSArray::cast(this)->length())->value()) :
04753 static_cast<uint32_t>(FixedArray::cast(elements())->length());
04754 return (index < length) &&
04755 !FixedArray::cast(elements())->get(index)->IsTheHole();
04756 } else {
04757 return element_dictionary()->FindNumberEntry(index) != -1;
04758 }
04759 }
04760
04761
04762 bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
04763
04764 if (IsAccessCheckNeeded() &&
04765 !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
04766 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
04767 return false;
04768 }
04769
04770
04771 if (HasIndexedInterceptor()) {
04772 return HasElementWithInterceptor(receiver, index);
04773 }
04774
04775 if (HasFastElements()) {
04776 uint32_t length = IsJSArray() ?
04777 static_cast<uint32_t>(
04778 Smi::cast(JSArray::cast(this)->length())->value()) :
04779 static_cast<uint32_t>(FixedArray::cast(elements())->length());
04780 if ((index < length) &&
04781 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
04782 } else {
04783 if (element_dictionary()->FindNumberEntry(index) != -1) return true;
04784 }
04785
04786
04787 if (this->IsStringObjectWithCharacterAt(index)) return true;
04788
04789 Object* pt = GetPrototype();
04790 if (pt == Heap::null_value()) return false;
04791 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
04792 }
04793
04794
04795 Object* JSObject::SetElementPostInterceptor(uint32_t index, Object* value) {
04796 if (HasFastElements()) return SetFastElement(index, value);
04797
04798
04799 ASSERT(!HasFastElements());
04800
04801 FixedArray* elms = FixedArray::cast(elements());
04802 Object* result = Dictionary::cast(elms)->AtNumberPut(index, value);
04803 if (result->IsFailure()) return result;
04804 if (elms != FixedArray::cast(result)) {
04805 set_elements(FixedArray::cast(result));
04806 }
04807
04808 if (IsJSArray()) {
04809 return JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
04810 }
04811
04812 return value;
04813 }
04814
04815
04816 Object* JSObject::SetElementWithInterceptor(uint32_t index, Object* value) {
04817
04818
04819 AssertNoContextChange ncc;
04820 HandleScope scope;
04821 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
04822 Handle<JSObject> this_handle(this);
04823 Handle<Object> value_handle(value);
04824 if (!interceptor->setter()->IsUndefined()) {
04825 v8::IndexedPropertySetter setter =
04826 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
04827 Handle<Object> data_handle(interceptor->data());
04828 LOG(ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
04829 v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
04830 v8::Utils::ToLocal(data_handle),
04831 v8::Utils::ToLocal(this_handle));
04832 v8::Handle<v8::Value> result;
04833 {
04834
04835 VMState state(OTHER);
04836 result = setter(index, v8::Utils::ToLocal(value_handle), info);
04837 }
04838 RETURN_IF_SCHEDULED_EXCEPTION();
04839 if (!result.IsEmpty()) return *value_handle;
04840 }
04841 Object* raw_result =
04842 this_handle->SetElementPostInterceptor(index, *value_handle);
04843 RETURN_IF_SCHEDULED_EXCEPTION();
04844 return raw_result;
04845 }
04846
04847
04848
04849
04850
04851 Object* JSObject::SetFastElement(uint32_t index, Object* value) {
04852 ASSERT(HasFastElements());
04853
04854 FixedArray* elms = FixedArray::cast(elements());
04855 uint32_t elms_length = static_cast<uint32_t>(elms->length());
04856
04857
04858 if (index < elms_length) {
04859 elms->set(index, value);
04860 if (IsJSArray()) {
04861
04862 uint32_t array_length = 0;
04863 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(),
04864 &array_length));
04865 if (index >= array_length) {
04866 JSArray::cast(this)->set_length(Smi::FromInt(index + 1),
04867 SKIP_WRITE_BARRIER);
04868 }
04869 }
04870 return value;
04871 }
04872
04873
04874 if ((index - elms_length) < kMaxGap) {
04875
04876 int new_capacity = NewElementsCapacity(index+1);
04877 if (new_capacity <= kMaxFastElementsLength ||
04878 !ShouldConvertToSlowElements(new_capacity)) {
04879 ASSERT(static_cast<uint32_t>(new_capacity) > index);
04880 Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
04881 if (obj->IsFailure()) return obj;
04882 SetFastElements(FixedArray::cast(obj));
04883 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(index + 1),
04884 SKIP_WRITE_BARRIER);
04885 FixedArray::cast(elements())->set(index, value);
04886 return value;
04887 }
04888 }
04889
04890
04891 Object* obj = NormalizeElements();
04892 if (obj->IsFailure()) return obj;
04893 ASSERT(!HasFastElements());
04894 return SetElement(index, value);
04895 }
04896
04897 Object* JSObject::SetElement(uint32_t index, Object* value) {
04898
04899 if (IsAccessCheckNeeded() &&
04900 !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) {
04901 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
04902 return value;
04903 }
04904
04905 if (IsJSGlobalProxy()) {
04906 Object* proto = GetPrototype();
04907 if (proto->IsNull()) return value;
04908 ASSERT(proto->IsJSGlobalObject());
04909 return JSObject::cast(proto)->SetElement(index, value);
04910 }
04911
04912
04913 if (HasIndexedInterceptor()) {
04914 return SetElementWithInterceptor(index, value);
04915 }
04916
04917
04918 if (HasFastElements()) return SetFastElement(index, value);
04919
04920
04921 ASSERT(!HasFastElements());
04922
04923
04924 FixedArray* elms = FixedArray::cast(elements());
04925 Dictionary* dictionary = Dictionary::cast(elms);
04926 Object* result = dictionary->AtNumberPut(index, value);
04927 if (result->IsFailure()) return result;
04928 if (elms != FixedArray::cast(result)) {
04929 set_elements(FixedArray::cast(result));
04930 }
04931
04932
04933 if (IsJSArray()) {
04934 JSArray* array = JSArray::cast(this);
04935 Object* return_value = array->JSArrayUpdateLengthFromIndex(index, value);
04936 if (return_value->IsFailure()) return return_value;
04937 }
04938
04939
04940 if (ShouldConvertToFastElements()) {
04941 uint32_t new_length = 0;
04942 if (IsJSArray()) {
04943 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length));
04944 } else {
04945 new_length = Dictionary::cast(elements())->max_number_key() + 1;
04946 }
04947 Object* obj = Heap::AllocateFixedArrayWithHoles(new_length);
04948 if (obj->IsFailure()) return obj;
04949 SetFastElements(FixedArray::cast(obj));
04950 #ifdef DEBUG
04951 if (FLAG_trace_normalization) {
04952 PrintF("Object elements are fast case again:\n");
04953 Print();
04954 }
04955 #endif
04956 }
04957
04958 return value;
04959 }
04960
04961
04962 Object* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, Object* value) {
04963 uint32_t old_len = 0;
04964 CHECK(Array::IndexFromObject(length(), &old_len));
04965
04966
04967 if (index >= old_len && index != 0xffffffff) {
04968 Object* len =
04969 Heap::NumberFromDouble(static_cast<double>(index) + 1);
04970 if (len->IsFailure()) return len;
04971 set_length(len);
04972 }
04973 return value;
04974 }
04975
04976
04977 Object* JSObject::GetElementPostInterceptor(JSObject* receiver,
04978 uint32_t index) {
04979
04980
04981 if (HasFastElements()) {
04982 FixedArray* elms = FixedArray::cast(elements());
04983 if (index < static_cast<uint32_t>(elms->length())) {
04984 Object* value = elms->get(index);
04985 if (!value->IsTheHole()) return value;
04986 }
04987 } else {
04988 Dictionary* dictionary = element_dictionary();
04989 int entry = dictionary->FindNumberEntry(index);
04990 if (entry != -1) {
04991 return dictionary->ValueAt(entry);
04992 }
04993 }
04994
04995
04996 Object* pt = GetPrototype();
04997 if (pt == Heap::null_value()) return Heap::undefined_value();
04998 return pt->GetElementWithReceiver(receiver, index);
04999 }
05000
05001
05002 Object* JSObject::GetElementWithInterceptor(JSObject* receiver,
05003 uint32_t index) {
05004
05005
05006 AssertNoContextChange ncc;
05007 HandleScope scope;
05008 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
05009 Handle<JSObject> this_handle(receiver);
05010 Handle<JSObject> holder_handle(this);
05011
05012 if (!interceptor->getter()->IsUndefined()) {
05013 Handle<Object> data_handle(interceptor->data());
05014 v8::IndexedPropertyGetter getter =
05015 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
05016 LOG(ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
05017 v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
05018 v8::Utils::ToLocal(data_handle),
05019 v8::Utils::ToLocal(holder_handle));
05020 v8::Handle<v8::Value> result;
05021 {
05022
05023 VMState state(OTHER);
05024 result = getter(index, info);
05025 }
05026 RETURN_IF_SCHEDULED_EXCEPTION();
05027 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
05028 }
05029
05030 Object* raw_result =
05031 holder_handle->GetElementPostInterceptor(*this_handle, index);
05032 RETURN_IF_SCHEDULED_EXCEPTION();
05033 return raw_result;
05034 }
05035
05036
05037 Object* JSObject::GetElementWithReceiver(JSObject* receiver, uint32_t index) {
05038
05039 if (IsAccessCheckNeeded() &&
05040 !Top::MayIndexedAccess(this, index, v8::ACCESS_GET)) {
05041 Top::ReportFailedAccessCheck(this, v8::ACCESS_GET);
05042 return Heap::undefined_value();
05043 }
05044
05045 if (HasIndexedInterceptor()) {
05046 return GetElementWithInterceptor(receiver, index);
05047 }
05048
05049
05050
05051 if (HasFastElements()) {
05052 FixedArray* elms = FixedArray::cast(elements());
05053 if (index < static_cast<uint32_t>(elms->length())) {
05054 Object* value = elms->get(index);
05055 if (!value->IsTheHole()) return value;
05056 }
05057 } else {
05058 Dictionary* dictionary = element_dictionary();
05059 int entry = dictionary->FindNumberEntry(index);
05060 if (entry != -1) {
05061 return dictionary->ValueAt(entry);
05062 }
05063 }
05064
05065 Object* pt = GetPrototype();
05066 if (pt == Heap::null_value()) return Heap::undefined_value();
05067 return pt->GetElementWithReceiver(receiver, index);
05068 }
05069
05070
05071 bool JSObject::HasDenseElements() {
05072 int capacity = 0;
05073 int number_of_elements = 0;
05074
05075 if (HasFastElements()) {
05076 FixedArray* elms = FixedArray::cast(elements());
05077 capacity = elms->length();
05078 for (int i = 0; i < capacity; i++) {
05079 if (!elms->get(i)->IsTheHole()) number_of_elements++;
05080 }
05081 } else {
05082 Dictionary* dictionary = Dictionary::cast(elements());
05083 capacity = dictionary->Capacity();
05084 number_of_elements = dictionary->NumberOfElements();
05085 }
05086
05087 if (capacity == 0) return true;
05088 return (number_of_elements > (capacity / 2));
05089 }
05090
05091
05092 bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
05093 ASSERT(HasFastElements());
05094
05095
05096
05097 int elements_length = FixedArray::cast(elements())->length();
05098 return !HasDenseElements() || ((new_capacity / 2) > elements_length);
05099 }
05100
05101
05102 bool JSObject::ShouldConvertToFastElements() {
05103 ASSERT(!HasFastElements());
05104 Dictionary* dictionary = Dictionary::cast(elements());
05105
05106 if (!HasDenseElements()) return false;
05107
05108
05109 if (dictionary->requires_slow_elements()) return false;
05110
05111
05112 if (IsAccessCheckNeeded()) return false;
05113
05114
05115
05116 uint32_t length = 0;
05117 if (IsJSArray()) {
05118 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &length));
05119 } else {
05120 length = dictionary->max_number_key();
05121 }
05122 return static_cast<uint32_t>(dictionary->Capacity()) >=
05123 (length / (2 * Dictionary::kElementSize));
05124 }
05125
05126
05127 Object* Dictionary::RemoveHoles() {
05128 int capacity = Capacity();
05129 Object* obj = Allocate(NumberOfElements());
05130 if (obj->IsFailure()) return obj;
05131 Dictionary* dict = Dictionary::cast(obj);
05132 uint32_t pos = 0;
05133 for (int i = 0; i < capacity; i++) {
05134 Object* k = KeyAt(i);
05135 if (IsKey(k)) {
05136 dict->AddNumberEntry(pos++, ValueAt(i), DetailsAt(i));
05137 }
05138 }
05139 return dict;
05140 }
05141
05142
05143 void Dictionary::CopyValuesTo(FixedArray* elements) {
05144 int pos = 0;
05145 int capacity = Capacity();
05146 for (int i = 0; i < capacity; i++) {
05147 Object* k = KeyAt(i);
05148 if (IsKey(k)) elements->set(pos++, ValueAt(i));
05149 }
05150 ASSERT(pos == elements->length());
05151 }
05152
05153
05154 Object* JSArray::RemoveHoles() {
05155 if (HasFastElements()) {
05156 int len = Smi::cast(length())->value();
05157 int pos = 0;
05158 FixedArray* elms = FixedArray::cast(elements());
05159 for (int index = 0; index < len; index++) {
05160 Object* e = elms->get(index);
05161 if (!e->IsTheHole()) {
05162 if (index != pos) elms->set(pos, e);
05163 pos++;
05164 }
05165 }
05166 set_length(Smi::FromInt(pos), SKIP_WRITE_BARRIER);
05167 for (int index = pos; index < len; index++) {
05168 elms->set_the_hole(index);
05169 }
05170 return this;
05171 }
05172
05173
05174 Dictionary* dict = element_dictionary();
05175 int length = dict->NumberOfElements();
05176
05177
05178 if (length <= kMaxFastElementsLength) {
05179 Object* obj = Heap::AllocateFixedArray(length);
05180 if (obj->IsFailure()) return obj;
05181 dict->CopyValuesTo(FixedArray::cast(obj));
05182 set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER);
05183 set_elements(FixedArray::cast(obj));
05184 return this;
05185 }
05186
05187
05188 Object* obj = dict->RemoveHoles();
05189 if (obj->IsFailure()) return obj;
05190 set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER);
05191 set_elements(Dictionary::cast(obj));
05192 return this;
05193 }
05194
05195
05196 InterceptorInfo* JSObject::GetNamedInterceptor() {
05197 ASSERT(map()->has_named_interceptor());
05198 JSFunction* constructor = JSFunction::cast(map()->constructor());
05199 Object* template_info = constructor->shared()->function_data();
05200 Object* result =
05201 FunctionTemplateInfo::cast(template_info)->named_property_handler();
05202 return InterceptorInfo::cast(result);
05203 }
05204
05205
05206 InterceptorInfo* JSObject::GetIndexedInterceptor() {
05207 ASSERT(map()->has_indexed_interceptor());
05208 JSFunction* constructor = JSFunction::cast(map()->constructor());
05209 Object* template_info = constructor->shared()->function_data();
05210 Object* result =
05211 FunctionTemplateInfo::cast(template_info)->indexed_property_handler();
05212 return InterceptorInfo::cast(result);
05213 }
05214
05215
05216 Object* JSObject::GetPropertyPostInterceptor(JSObject* receiver,
05217 String* name,
05218 PropertyAttributes* attributes) {
05219
05220 LookupResult result;
05221 LocalLookupRealNamedProperty(name, &result);
05222 if (result.IsValid()) return GetProperty(receiver, &result, name, attributes);
05223
05224 Object* pt = GetPrototype();
05225 *attributes = ABSENT;
05226 if (pt == Heap::null_value()) return Heap::undefined_value();
05227 return pt->GetPropertyWithReceiver(receiver, name, attributes);
05228 }
05229
05230
05231 Object* JSObject::GetPropertyWithInterceptor(JSObject* receiver,
05232 String* name,
05233 PropertyAttributes* attributes) {
05234 HandleScope scope;
05235 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
05236 Handle<JSObject> receiver_handle(receiver);
05237 Handle<JSObject> holder_handle(this);
05238 Handle<String> name_handle(name);
05239 Handle<Object> data_handle(interceptor->data());
05240
05241 if (!interceptor->getter()->IsUndefined()) {
05242 v8::NamedPropertyGetter getter =
05243 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
05244 LOG(ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
05245 v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle),
05246 v8::Utils::ToLocal(data_handle),
05247 v8::Utils::ToLocal(holder_handle));
05248 v8::Handle<v8::Value> result;
05249 {
05250
05251 VMState state(OTHER);
05252 result = getter(v8::Utils::ToLocal(name_handle), info);
05253 }
05254 RETURN_IF_SCHEDULED_EXCEPTION();
05255 if (!result.IsEmpty()) {
05256 *attributes = NONE;
05257 return *v8::Utils::OpenHandle(*result);
05258 }
05259 }
05260
05261 Object* raw_result = holder_handle->GetPropertyPostInterceptor(
05262 *receiver_handle,
05263 *name_handle,
05264 attributes);
05265 RETURN_IF_SCHEDULED_EXCEPTION();
05266 return raw_result;
05267 }
05268
05269
05270 bool JSObject::HasRealNamedProperty(String* key) {
05271
05272 if (IsAccessCheckNeeded() &&
05273 !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) {
05274 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
05275 return false;
05276 }
05277
05278 LookupResult result;
05279 LocalLookupRealNamedProperty(key, &result);
05280 if (result.IsValid()) {
05281 switch (result.type()) {
05282 case NORMAL:
05283 case FIELD:
05284 case CALLBACKS:
05285 case CONSTANT_FUNCTION:
05286 return true;
05287 case INTERCEPTOR:
05288 case MAP_TRANSITION:
05289 case CONSTANT_TRANSITION:
05290 case NULL_DESCRIPTOR:
05291 return false;
05292 default:
05293 UNREACHABLE();
05294 }
05295 }
05296
05297 return false;
05298 }
05299
05300
05301 bool JSObject::HasRealElementProperty(uint32_t index) {
05302
05303 if (IsAccessCheckNeeded() &&
05304 !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
05305 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
05306 return false;
05307 }
05308
05309
05310 if (this->IsStringObjectWithCharacterAt(index)) return true;
05311
05312 if (HasFastElements()) {
05313 uint32_t length = IsJSArray() ?
05314 static_cast<uint32_t>(
05315 Smi::cast(JSArray::cast(this)->length())->value()) :
05316 static_cast<uint32_t>(FixedArray::cast(elements())->length());
05317 return (index < length) &&
05318 !FixedArray::cast(elements())->get(index)->IsTheHole();
05319 }
05320 return element_dictionary()->FindNumberEntry(index) != -1;
05321 }
05322
05323
05324 bool JSObject::HasRealNamedCallbackProperty(String* key) {
05325
05326 if (IsAccessCheckNeeded() &&
05327 !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) {
05328 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
05329 return false;
05330 }
05331
05332 LookupResult result;
05333 LocalLookupRealNamedProperty(key, &result);
05334 return result.IsValid() && (result.type() == CALLBACKS);
05335 }
05336
05337
05338 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
05339 if (HasFastProperties()) {
05340 int result = 0;
05341 for (DescriptorReader r(map()->instance_descriptors());
05342 !r.eos();
05343 r.advance()) {
05344 PropertyDetails details = r.GetDetails();
05345 if (!details.IsTransition() && (details.attributes() & filter) == 0) {
05346 result++;
05347 }
05348 }
05349 return result;
05350 } else {
05351 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
05352 }
05353 }
05354
05355
05356 int JSObject::NumberOfEnumProperties() {
05357 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
05358 }
05359
05360
05361 void FixedArray::Swap(int i, int j) {
05362 Object* temp = get(i);
05363 set(i, get(j));
05364 set(j, temp);
05365 }
05366
05367
05368 static void InsertionSortPairs(FixedArray* content, FixedArray* smis) {
05369 int len = smis->length();
05370 for (int i = 1; i < len; i++) {
05371 int j = i;
05372 while (j > 0 &&
05373 Smi::cast(smis->get(j-1))->value() >
05374 Smi::cast(smis->get(j))->value()) {
05375 smis->Swap(j-1, j);
05376 content->Swap(j-1, j);
05377 j--;
05378 }
05379 }
05380 }
05381
05382
05383 void HeapSortPairs(FixedArray* content, FixedArray* smis) {
05384
05385 ASSERT(content->length() == smis->length());
05386 int len = smis->length();
05387
05388
05389 for (int i = 1; i < len; ++i) {
05390 int child_index = i;
05391 while (child_index > 0) {
05392 int parent_index = ((child_index + 1) >> 1) - 1;
05393 int parent_value = Smi::cast(smis->get(parent_index))->value();
05394 int child_value = Smi::cast(smis->get(child_index))->value();
05395 if (parent_value < child_value) {
05396 content->Swap(parent_index, child_index);
05397 smis->Swap(parent_index, child_index);
05398 } else {
05399 break;
05400 }
05401 child_index = parent_index;
05402 }
05403 }
05404
05405
05406 for (int i = len - 1; i > 0; --i) {
05407
05408 content->Swap(0, i);
05409 smis->Swap(0, i);
05410
05411 int parent_index = 0;
05412 while (true) {
05413 int child_index = ((parent_index + 1) << 1) - 1;
05414 if (child_index >= i) break;
05415 uint32_t child1_value = Smi::cast(smis->get(child_index))->value();
05416 uint32_t child2_value = Smi::cast(smis->get(child_index + 1))->value();
05417 uint32_t parent_value = Smi::cast(smis->get(parent_index))->value();
05418 if (child_index + 1 >= i || child1_value > child2_value) {
05419 if (parent_value > child1_value) break;
05420 content->Swap(parent_index, child_index);
05421 smis->Swap(parent_index, child_index);
05422 parent_index = child_index;
05423 } else {
05424 if (parent_value > child2_value) break;
05425 content->Swap(parent_index, child_index + 1);
05426 smis->Swap(parent_index, child_index + 1);
05427 parent_index = child_index + 1;
05428 }
05429 }
05430 }
05431 }
05432
05433
05434
05435 void FixedArray::SortPairs(FixedArray* smis) {
05436 ASSERT(this->length() == smis->length());
05437 int len = smis->length();
05438
05439 if (len <= 10) {
05440 InsertionSortPairs(this, smis);
05441 return;
05442 }
05443
05444 int min_index = Smi::cast(smis->get(0))->value();
05445 int max_index = min_index;
05446 int i;
05447 for (i = 1; i < len; i++) {
05448 if (Smi::cast(smis->get(i))->value() < min_index) {
05449 min_index = Smi::cast(smis->get(i))->value();
05450 } else if (Smi::cast(smis->get(i))->value() > max_index) {
05451 max_index = Smi::cast(smis->get(i))->value();
05452 }
05453 }
05454 if (max_index - min_index + 1 == len) {
05455
05456
05457
05458 for (i = 0; i < len; i++) {
05459 int p;
05460 int j = 0;
05461
05462
05463 while ((p = Smi::cast(smis->get(i))->value() - min_index) != i &&
05464 j++ < len) {
05465 this->Swap(i, p);
05466 smis->Swap(i, p);
05467 }
05468 }
05469 } else {
05470 HeapSortPairs(this, smis);
05471 return;
05472 }
05473 }
05474
05475
05476
05477
05478
05479 void JSObject::GetLocalPropertyNames(FixedArray* storage) {
05480 ASSERT(storage->length() ==
05481 NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE)));
05482 int index = 0;
05483 if (HasFastProperties()) {
05484 for (DescriptorReader r(map()->instance_descriptors());
05485 !r.eos();
05486 r.advance()) {
05487 if (!r.IsTransition()) {
05488 storage->set(index++, r.GetKey());
05489 }
05490 }
05491 ASSERT(storage->length() == index);
05492 } else {
05493 property_dictionary()->CopyKeysTo(storage);
05494 }
05495 }
05496
05497
05498 int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
05499 return GetLocalElementKeys(NULL, filter);
05500 }
05501
05502
05503 int JSObject::NumberOfEnumElements() {
05504 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
05505 }
05506
05507
05508 int JSObject::GetLocalElementKeys(FixedArray* storage,
05509 PropertyAttributes filter) {
05510 int counter = 0;
05511 if (HasFastElements()) {
05512 int length = IsJSArray()
05513 ? Smi::cast(JSArray::cast(this)->length())->value()
05514 : FixedArray::cast(elements())->length();
05515 for (int i = 0; i < length; i++) {
05516 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
05517 if (storage) {
05518 storage->set(counter, Smi::FromInt(i), SKIP_WRITE_BARRIER);
05519 }
05520 counter++;
05521 }
05522 }
05523 ASSERT(!storage || storage->length() >= counter);
05524 } else {
05525 if (storage) {
05526 element_dictionary()->CopyKeysTo(storage, filter);
05527 }
05528 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
05529 }
05530
05531 if (this->IsJSValue()) {
05532 Object* val = JSValue::cast(this)->value();
05533 if (val->IsString()) {
05534 String* str = String::cast(val);
05535 if (storage) {
05536 for (int i = 0; i < str->length(); i++) {
05537 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER);
05538 }
05539 }
05540 counter += str->length();
05541 }
05542 }
05543 ASSERT(!storage || storage->length() == counter);
05544 return counter;
05545 }
05546
05547
05548 int JSObject::GetEnumElementKeys(FixedArray* storage) {
05549 return GetLocalElementKeys(storage,
05550 static_cast<PropertyAttributes>(DONT_ENUM));
05551 }
05552
05553
05554
05555
05556 class NumberKey : public HashTableKey {
05557 public:
05558 explicit NumberKey(uint32_t number) : number_(number) { }
05559
05560 private:
05561 bool IsMatch(Object* number) {
05562 return number_ == ToUint32(number);
05563 }
05564
05565
05566
05567 static uint32_t ComputeHash(uint32_t key) {
05568 uint32_t hash = key;
05569 hash = ~hash + (hash << 15);
05570 hash = hash ^ (hash >> 12);
05571 hash = hash + (hash << 2);
05572 hash = hash ^ (hash >> 4);
05573 hash = hash * 2057;
05574 hash = hash ^ (hash >> 16);
05575 return hash;
05576 }
05577
05578 uint32_t Hash() { return ComputeHash(number_); }
05579
05580 HashFunction GetHashFunction() { return NumberHash; }
05581
05582 Object* GetObject() {
05583 return Heap::NumberFromDouble(number_);
05584 }
05585
05586 static uint32_t NumberHash(Object* obj) {
05587 return ComputeHash(ToUint32(obj));
05588 }
05589
05590 static uint32_t ToUint32(Object* obj) {
05591 ASSERT(obj->IsNumber());
05592 return static_cast<uint32_t>(obj->Number());
05593 }
05594
05595 bool IsStringKey() { return false; }
05596
05597 uint32_t number_;
05598 };
05599
05600
05601
05602 class StringKey : public HashTableKey {
05603 public:
05604 explicit StringKey(String* string) : string_(string) { }
05605
05606 bool IsMatch(Object* string) {
05607 return string_->Equals(String::cast(string));
05608 }
05609
05610 uint32_t Hash() { return StringHash(string_); }
05611
05612 HashFunction GetHashFunction() { return StringHash; }
05613
05614 Object* GetObject() { return string_; }
05615
05616 static uint32_t StringHash(Object* obj) {
05617 return String::cast(obj)->Hash();
05618 }
05619
05620 bool IsStringKey() { return true; }
05621
05622 String* string_;
05623 };
05624
05625
05626 class RegExpKey : public HashTableKey {
05627 public:
05628 RegExpKey(String* string, JSRegExp::Flags flags)
05629 : string_(string),
05630 flags_(Smi::FromInt(flags.value())) { }
05631
05632 bool IsMatch(Object* obj) {
05633 FixedArray* val = FixedArray::cast(obj);
05634 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
05635 && (flags_ == val->get(JSRegExp::kFlagsIndex));
05636 }
05637
05638 uint32_t Hash() { return RegExpHash(string_, flags_); }
05639
05640 HashFunction GetHashFunction() { return RegExpObjectHash; }
05641
05642 Object* GetObject() {
05643
05644
05645 UNREACHABLE();
05646 return NULL;
05647 }
05648
05649 static uint32_t RegExpObjectHash(Object* obj) {
05650 FixedArray* val = FixedArray::cast(obj);
05651 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
05652 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
05653 }
05654
05655 static uint32_t RegExpHash(String* string, Smi* flags) {
05656 return string->Hash() + flags->value();
05657 }
05658
05659 bool IsStringKey() { return false; }
05660
05661 String* string_;
05662 Smi* flags_;
05663 };
05664
05665
05666 class Utf8SymbolKey : public HashTableKey {
05667 public:
05668 explicit Utf8SymbolKey(Vector<const char> string)
05669 : string_(string), length_field_(0) { }
05670
05671 bool IsMatch(Object* string) {
05672 return String::cast(string)->IsEqualTo(string_);
05673 }
05674
05675 HashFunction GetHashFunction() {
05676 return StringHash;
05677 }
05678
05679 uint32_t Hash() {
05680 if (length_field_ != 0) return length_field_ >> String::kHashShift;
05681 unibrow::Utf8InputBuffer<> buffer(string_.start(),
05682 static_cast<unsigned>(string_.length()));
05683 chars_ = buffer.Length();
05684 length_field_ = String::ComputeLengthAndHashField(&buffer, chars_);
05685 return length_field_ >> String::kHashShift;
05686 }
05687
05688 Object* GetObject() {
05689 if (length_field_ == 0) Hash();
05690 unibrow::Utf8InputBuffer<> buffer(string_.start(),
05691 static_cast<unsigned>(string_.length()));
05692 return Heap::AllocateSymbol(&buffer, chars_, length_field_);
05693 }
05694
05695 static uint32_t StringHash(Object* obj) {
05696 return String::cast(obj)->Hash();
05697 }
05698
05699 bool IsStringKey() { return true; }
05700
05701 Vector<const char> string_;
05702 uint32_t length_field_;
05703 int chars_;
05704 };
05705
05706
05707
05708 class SymbolKey : public HashTableKey {
05709 public:
05710 explicit SymbolKey(String* string) : string_(string) { }
05711
05712 HashFunction GetHashFunction() {
05713 return StringHash;
05714 }
05715
05716 bool IsMatch(Object* string) {
05717 return String::cast(string)->Equals(string_);
05718 }
05719
05720 uint32_t Hash() { return string_->Hash(); }
05721
05722 Object* GetObject() {
05723
05724
05725 if (string_->IsConsString()) {
05726 ConsString* cons_string = ConsString::cast(string_);
05727 cons_string->TryFlatten();
05728 if (cons_string->second() == Heap::empty_string()) {
05729 string_ = String::cast(cons_string->first());
05730 }
05731 }
05732
05733 Map* map = Heap::SymbolMapForString(string_);
05734 if (map != NULL) {
05735 string_->set_map(map);
05736 return string_;
05737 }
05738
05739 StringInputBuffer buffer(string_);
05740 return Heap::AllocateSymbol(&buffer,
05741 string_->length(),
05742 string_->length_field());
05743 }
05744
05745 static uint32_t StringHash(Object* obj) {
05746 return String::cast(obj)->Hash();
05747 }
05748
05749 bool IsStringKey() { return true; }
05750
05751 String* string_;
05752 };
05753
05754
05755 template<int prefix_size, int element_size>
05756 void HashTable<prefix_size, element_size>::IteratePrefix(ObjectVisitor* v) {
05757 IteratePointers(v, 0, kElementsStartOffset);
05758 }
05759
05760
05761 template<int prefix_size, int element_size>
05762 void HashTable<prefix_size, element_size>::IterateElements(ObjectVisitor* v) {
05763 IteratePointers(v,
05764 kElementsStartOffset,
05765 kHeaderSize + length() * kPointerSize);
05766 }
05767
05768
05769 template<int prefix_size, int element_size>
05770 Object* HashTable<prefix_size, element_size>::Allocate(int at_least_space_for) {
05771 int capacity = RoundUpToPowerOf2(at_least_space_for);
05772 if (capacity < 4) capacity = 4;
05773 Object* obj = Heap::AllocateHashTable(EntryToIndex(capacity));
05774 if (!obj->IsFailure()) {
05775 HashTable::cast(obj)->SetNumberOfElements(0);
05776 HashTable::cast(obj)->SetCapacity(capacity);
05777 }
05778 return obj;
05779 }
05780
05781
05782
05783 template <int prefix_size, int element_size>
05784 int HashTable<prefix_size, element_size>::FindEntry(HashTableKey* key) {
05785 uint32_t nof = NumberOfElements();
05786 if (nof == 0) return -1;
05787
05788 uint32_t capacity = Capacity();
05789 uint32_t hash = key->Hash();
05790 uint32_t entry = GetProbe(hash, 0, capacity);
05791
05792 Object* element = KeyAt(entry);
05793 uint32_t passed_elements = 0;
05794 if (!element->IsNull()) {
05795 if (!element->IsUndefined() && key->IsMatch(element)) return entry;
05796 if (++passed_elements == nof) return -1;
05797 }
05798 for (uint32_t i = 1; !element->IsUndefined(); i++) {
05799 entry = GetProbe(hash, i, capacity);
05800 element = KeyAt(entry);
05801 if (!element->IsNull()) {
05802 if (!element->IsUndefined() && key->IsMatch(element)) return entry;
05803 if (++passed_elements == nof) return -1;
05804 }
05805 }
05806 return -1;
05807 }
05808
05809
05810 template<int prefix_size, int element_size>
05811 Object* HashTable<prefix_size, element_size>::EnsureCapacity(
05812 int n, HashTableKey* key) {
05813 int capacity = Capacity();
05814 int nof = NumberOfElements() + n;
05815
05816 if (nof + (nof >> 2) <= capacity) return this;
05817
05818 Object* obj = Allocate(nof * 2);
05819 if (obj->IsFailure()) return obj;
05820 HashTable* table = HashTable::cast(obj);
05821 WriteBarrierMode mode = table->GetWriteBarrierMode();
05822
05823
05824 for (int i = kPrefixStartIndex; i < kPrefixStartIndex + prefix_size; i++) {
05825 table->set(i, get(i), mode);
05826 }
05827
05828 uint32_t (*Hash)(Object* key) = key->GetHashFunction();
05829 for (int i = 0; i < capacity; i++) {
05830 uint32_t from_index = EntryToIndex(i);
05831 Object* key = get(from_index);
05832 if (IsKey(key)) {
05833 uint32_t insertion_index =
05834 EntryToIndex(table->FindInsertionEntry(key, Hash(key)));
05835 for (int j = 0; j < element_size; j++) {
05836 table->set(insertion_index + j, get(from_index + j), mode);
05837 }
05838 }
05839 }
05840 table->SetNumberOfElements(NumberOfElements());
05841 return table;
05842 }
05843
05844
05845 template<int prefix_size, int element_size>
05846 uint32_t HashTable<prefix_size, element_size>::FindInsertionEntry(
05847 Object* key,
05848 uint32_t hash) {
05849 uint32_t capacity = Capacity();
05850 uint32_t entry = GetProbe(hash, 0, capacity);
05851 Object* element = KeyAt(entry);
05852
05853 for (uint32_t i = 1; !(element->IsUndefined() || element->IsNull()); i++) {
05854 entry = GetProbe(hash, i, capacity);
05855 element = KeyAt(entry);
05856 }
05857
05858 return entry;
05859 }
05860
05861
05862
05863 template class HashTable<0, 1>;
05864
05865
05866
05867 template class HashTable<2, 3>;
05868
05869
05870
05871 template class HashTable<0, 2>;
05872
05873
05874 Object* SymbolTable::LookupString(String* string, Object** s) {
05875 SymbolKey key(string);
05876 return LookupKey(&key, s);
05877 }
05878
05879
05880 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
05881 SymbolKey key(string);
05882 int entry = FindEntry(&key);
05883 if (entry == -1) {
05884 return false;
05885 } else {
05886 String* result = String::cast(KeyAt(entry));
05887 ASSERT(result->is_symbol());
05888 *symbol = result;
05889 return true;
05890 }
05891 }
05892
05893
05894 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
05895 Utf8SymbolKey key(str);
05896 return LookupKey(&key, s);
05897 }
05898
05899
05900 Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
05901 int entry = FindEntry(key);
05902
05903
05904 if (entry != -1) {
05905 *s = KeyAt(entry);
05906 return this;
05907 }
05908
05909
05910 Object* obj = EnsureCapacity(1, key);
05911 if (obj->IsFailure()) return obj;
05912
05913
05914 Object* symbol = key->GetObject();
05915 if (symbol->IsFailure()) return symbol;
05916
05917
05918
05919
05920 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
05921
05922
05923 entry = table->FindInsertionEntry(symbol, key->Hash());
05924 table->set(EntryToIndex(entry), symbol);
05925 table->ElementAdded();
05926 *s = symbol;
05927 return table;
05928 }
05929
05930
05931 Object* CompilationCacheTable::Lookup(String* src) {
05932 StringKey key(src);
05933 int entry = FindEntry(&key);
05934 if (entry == -1) return Heap::undefined_value();
05935 return get(EntryToIndex(entry) + 1);
05936 }
05937
05938
05939 Object* CompilationCacheTable::LookupRegExp(String* src,
05940 JSRegExp::Flags flags) {
05941 RegExpKey key(src, flags);
05942 int entry = FindEntry(&key);
05943 if (entry == -1) return Heap::undefined_value();
05944 return get(EntryToIndex(entry) + 1);
05945 }
05946
05947
05948 Object* CompilationCacheTable::Put(String* src, Object* value) {
05949 StringKey key(src);
05950 Object* obj = EnsureCapacity(1, &key);
05951 if (obj->IsFailure()) return obj;
05952
05953 CompilationCacheTable* cache =
05954 reinterpret_cast<CompilationCacheTable*>(obj);
05955 int entry = cache->FindInsertionEntry(src, key.Hash());
05956 cache->set(EntryToIndex(entry), src);
05957 cache->set(EntryToIndex(entry) + 1, value);
05958 cache->ElementAdded();
05959 return cache;
05960 }
05961
05962
05963 Object* CompilationCacheTable::PutRegExp(String* src,
05964 JSRegExp::Flags flags,
05965 FixedArray* value) {
05966 RegExpKey key(src, flags);
05967 Object* obj = EnsureCapacity(1, &key);
05968 if (obj->IsFailure()) return obj;
05969
05970 CompilationCacheTable* cache =
05971 reinterpret_cast<CompilationCacheTable*>(obj);
05972 int entry = cache->FindInsertionEntry(value, key.Hash());
05973 cache->set(EntryToIndex(entry), value);
05974 cache->set(EntryToIndex(entry) + 1, value);
05975 cache->ElementAdded();
05976 return cache;
05977 }
05978
05979
05980
05981 class SymbolsKey : public HashTableKey {
05982 public:
05983 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
05984
05985 bool IsMatch(Object* symbols) {
05986 FixedArray* o = FixedArray::cast(symbols);
05987 int len = symbols_->length();
05988 if (o->length() != len) return false;
05989 for (int i = 0; i < len; i++) {
05990 if (o->get(i) != symbols_->get(i)) return false;
05991 }
05992 return true;
05993 }
05994
05995 uint32_t Hash() { return SymbolsHash(symbols_); }
05996
05997 HashFunction GetHashFunction() { return SymbolsHash; }
05998
05999 Object* GetObject() { return symbols_; }
06000
06001 static uint32_t SymbolsHash(Object* obj) {
06002 FixedArray* symbols = FixedArray::cast(obj);
06003 int len = symbols->length();
06004 uint32_t hash = 0;
06005 for (int i = 0; i < len; i++) {
06006 hash ^= String::cast(symbols->get(i))->Hash();
06007 }
06008 return hash;
06009 }
06010
06011 bool IsStringKey() { return false; }
06012
06013 private:
06014 FixedArray* symbols_;
06015 };
06016
06017
06018
06019 class MapNameKey : public HashTableKey {
06020 public:
06021 MapNameKey(Map* map, String* name)
06022 : map_(map), name_(name) { }
06023
06024 bool IsMatch(Object* other) {
06025 if (!other->IsFixedArray()) return false;
06026 FixedArray* pair = FixedArray::cast(other);
06027 Map* map = Map::cast(pair->get(0));
06028 if (map != map_) return false;
06029 String* name = String::cast(pair->get(1));
06030 return name->Equals(name_);
06031 }
06032
06033 typedef uint32_t (*HashFunction)(Object* obj);
06034
06035 virtual HashFunction GetHashFunction() { return MapNameHash; }
06036
06037 static uint32_t MapNameHashHelper(Map* map, String* name) {
06038 return reinterpret_cast<uint32_t>(map) ^ name->Hash();
06039 }
06040
06041 static uint32_t MapNameHash(Object* obj) {
06042 FixedArray* pair = FixedArray::cast(obj);
06043 Map* map = Map::cast(pair->get(0));
06044 String* name = String::cast(pair->get(1));
06045 return MapNameHashHelper(map, name);
06046 }
06047
06048 virtual uint32_t Hash() {
06049 return MapNameHashHelper(map_, name_);
06050 }
06051
06052 virtual Object* GetObject() {
06053 Object* obj = Heap::AllocateFixedArray(2);
06054 if (obj->IsFailure()) return obj;
06055 FixedArray* pair = FixedArray::cast(obj);
06056 pair->set(0, map_);
06057 pair->set(1, name_);
06058 return pair;
06059 }
06060
06061 virtual bool IsStringKey() { return false; }
06062
06063 private:
06064 Map* map_;
06065 String* name_;
06066 };
06067
06068
06069 Object* MapCache::Lookup(FixedArray* array) {
06070 SymbolsKey key(array);
06071 int entry = FindEntry(&key);
06072 if (entry == -1) return Heap::undefined_value();
06073 return get(EntryToIndex(entry) + 1);
06074 }
06075
06076
06077 Object* MapCache::Put(FixedArray* array, Map* value) {
06078 SymbolsKey key(array);
06079 Object* obj = EnsureCapacity(1, &key);
06080 if (obj->IsFailure()) return obj;
06081
06082 MapCache* cache = reinterpret_cast<MapCache*>(obj);
06083 int entry = cache->FindInsertionEntry(array, key.Hash());
06084 cache->set(EntryToIndex(entry), array);
06085 cache->set(EntryToIndex(entry) + 1, value);
06086 cache->ElementAdded();
06087 return cache;
06088 }
06089
06090
06091 int LookupCache::Lookup(Map* map, String* name) {
06092 MapNameKey key(map, name);
06093 int entry = FindEntry(&key);
06094 if (entry == -1) return kNotFound;
06095 return Smi::cast(get(EntryToIndex(entry) + 1))->value();
06096 }
06097
06098
06099 Object* LookupCache::Put(Map* map, String* name, int value) {
06100 MapNameKey key(map, name);
06101 Object* obj = EnsureCapacity(1, &key);
06102 if (obj->IsFailure()) return obj;
06103 Object* k = key.GetObject();
06104 if (k->IsFailure()) return k;
06105
06106 LookupCache* cache = reinterpret_cast<LookupCache*>(obj);
06107 int entry = cache->FindInsertionEntry(k, key.Hash());
06108 int index = EntryToIndex(entry);
06109 cache->set(index, k);
06110 cache->set(index + 1, Smi::FromInt(value), SKIP_WRITE_BARRIER);
06111 cache->ElementAdded();
06112 return cache;
06113 }
06114
06115
06116 Object* Dictionary::Allocate(int at_least_space_for) {
06117 Object* obj = DictionaryBase::Allocate(at_least_space_for);
06118
06119 if (!obj->IsFailure()) {
06120 Dictionary::cast(obj)->
06121 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
06122 }
06123 return obj;
06124 }
06125
06126
06127 Object* Dictionary::GenerateNewEnumerationIndices() {
06128 int length = NumberOfElements();
06129
06130
06131 Object* obj = Heap::AllocateFixedArray(length);
06132 if (obj->IsFailure()) return obj;
06133 FixedArray* iteration_order = FixedArray::cast(obj);
06134 for (int i = 0; i < length; i++) {
06135 iteration_order->set(i, Smi::FromInt(i), SKIP_WRITE_BARRIER);
06136 }
06137
06138
06139 obj = Heap::AllocateFixedArray(length);
06140 if (obj->IsFailure()) return obj;
06141 FixedArray* enumeration_order = FixedArray::cast(obj);
06142
06143
06144 int capacity = Capacity();
06145 int pos = 0;
06146 for (int i = 0; i < capacity; i++) {
06147 if (IsKey(KeyAt(i))) {
06148 enumeration_order->set(pos++,
06149 Smi::FromInt(DetailsAt(i).index()),
06150 SKIP_WRITE_BARRIER);
06151 }
06152 }
06153
06154
06155 iteration_order->SortPairs(enumeration_order);
06156
06157
06158 for (int i = 0; i < length; i++) {
06159 int index = Smi::cast(iteration_order->get(i))->value();
06160 int enum_index = PropertyDetails::kInitialIndex + i;
06161 enumeration_order->set(index,
06162 Smi::FromInt(enum_index),
06163 SKIP_WRITE_BARRIER);
06164 }
06165
06166
06167 capacity = Capacity();
06168 pos = 0;
06169 for (int i = 0; i < capacity; i++) {
06170 if (IsKey(KeyAt(i))) {
06171 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
06172 PropertyDetails details = DetailsAt(i);
06173 PropertyDetails new_details =
06174 PropertyDetails(details.attributes(), details.type(), enum_index);
06175 DetailsAtPut(i, new_details);
06176 }
06177 }
06178
06179
06180 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
06181 return this;
06182 }
06183
06184
06185 Object* Dictionary::EnsureCapacity(int n, HashTableKey* key) {
06186
06187 if (key->IsStringKey() &&
06188 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
06189
06190 Object* result = GenerateNewEnumerationIndices();
06191 if (result->IsFailure()) return result;
06192 }
06193 return DictionaryBase::EnsureCapacity(n, key);
06194 }
06195
06196
06197 void Dictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
06198
06199 if (from >= to) return;
06200
06201 int removed_entries = 0;
06202 Object* sentinel = Heap::null_value();
06203 int capacity = Capacity();
06204 for (int i = 0; i < capacity; i++) {
06205 Object* key = KeyAt(i);
06206 if (key->IsNumber()) {
06207 uint32_t number = static_cast<uint32_t>(key->Number());
06208 if (from <= number && number < to) {
06209 SetEntry(i, sentinel, sentinel, Smi::FromInt(0));
06210 removed_entries++;
06211 }
06212 }
06213 }
06214
06215
06216 SetNumberOfElements(NumberOfElements() - removed_entries);
06217 }
06218
06219
06220 Object* Dictionary::DeleteProperty(int entry) {
06221 PropertyDetails details = DetailsAt(entry);
06222 if (details.IsDontDelete()) return Heap::false_value();
06223 SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0));
06224 ElementRemoved();
06225 return Heap::true_value();
06226 }
06227
06228
06229 int Dictionary::FindStringEntry(String* key) {
06230 StringKey k(key);
06231 return FindEntry(&k);
06232 }
06233
06234
06235 int Dictionary::FindNumberEntry(uint32_t index) {
06236 NumberKey k(index);
06237 return FindEntry(&k);
06238 }
06239
06240
06241 Object* Dictionary::AtPut(HashTableKey* key, Object* value) {
06242 int entry = FindEntry(key);
06243
06244
06245 if (entry != -1) {
06246 ValueAtPut(entry, value);
06247 return this;
06248 }
06249
06250
06251 Object* obj = EnsureCapacity(1, key);
06252 if (obj->IsFailure()) return obj;
06253 Object* k = key->GetObject();
06254 if (k->IsFailure()) return k;
06255 PropertyDetails details = PropertyDetails(NONE, NORMAL);
06256 Dictionary::cast(obj)->AddEntry(k, value, details, key->Hash());
06257 return obj;
06258 }
06259
06260
06261 Object* Dictionary::Add(HashTableKey* key, Object* value,
06262 PropertyDetails details) {
06263
06264 Object* obj = EnsureCapacity(1, key);
06265 if (obj->IsFailure()) return obj;
06266
06267 Object* k = key->GetObject();
06268 if (k->IsFailure()) return k;
06269 Dictionary::cast(obj)->AddEntry(k, value, details, key->Hash());
06270 return obj;
06271 }
06272
06273
06274
06275 void Dictionary::AddEntry(Object* key,
06276 Object* value,
06277 PropertyDetails details,
06278 uint32_t hash) {
06279 uint32_t entry = FindInsertionEntry(key, hash);
06280
06281 if (details.index() == 0 && key->IsString()) {
06282
06283
06284 int index = NextEnumerationIndex();
06285 details = PropertyDetails(details.attributes(), details.type(), index);
06286 SetNextEnumerationIndex(index + 1);
06287 }
06288 SetEntry(entry, key, value, details);
06289 ASSERT(KeyAt(entry)->IsNumber() || KeyAt(entry)->IsString());
06290 ElementAdded();
06291 }
06292
06293
06294 void Dictionary::UpdateMaxNumberKey(uint32_t key) {
06295
06296
06297 if (requires_slow_elements()) return;
06298
06299
06300 if (key > kRequiresSlowElementsLimit) {
06301 set(kMaxNumberKeyIndex,
06302 Smi::FromInt(kRequiresSlowElementsMask),
06303 SKIP_WRITE_BARRIER);
06304 return;
06305 }
06306
06307 Object* max_index_object = get(kMaxNumberKeyIndex);
06308 if (!max_index_object->IsSmi() || max_number_key() < key) {
06309 set(kMaxNumberKeyIndex,
06310 Smi::FromInt(key << kRequiresSlowElementsTagSize),
06311 SKIP_WRITE_BARRIER);
06312 }
06313 }
06314
06315
06316 Object* Dictionary::AddStringEntry(String* key,
06317 Object* value,
06318 PropertyDetails details) {
06319 StringKey k(key);
06320 SLOW_ASSERT(FindEntry(&k) == -1);
06321 return Add(&k, value, details);
06322 }
06323
06324
06325 Object* Dictionary::AddNumberEntry(uint32_t key,
06326 Object* value,
06327 PropertyDetails details) {
06328 NumberKey k(key);
06329 UpdateMaxNumberKey(key);
06330 SLOW_ASSERT(FindEntry(&k) == -1);
06331 return Add(&k, value, details);
06332 }
06333
06334
06335 Object* Dictionary::AtStringPut(String* key, Object* value) {
06336 StringKey k(key);
06337 return AtPut(&k, value);
06338 }
06339
06340
06341 Object* Dictionary::AtNumberPut(uint32_t key, Object* value) {
06342 NumberKey k(key);
06343 UpdateMaxNumberKey(key);
06344 return AtPut(&k, value);
06345 }
06346
06347
06348 Object* Dictionary::SetOrAddStringEntry(String* key,
06349 Object* value,
06350 PropertyDetails details) {
06351 StringKey k(key);
06352 int entry = FindEntry(&k);
06353 if (entry == -1) return AddStringEntry(key, value, details);
06354
06355 details = PropertyDetails(details.attributes(),
06356 details.type(),
06357 DetailsAt(entry).index());
06358 SetEntry(entry, key, value, details);
06359 return this;
06360 }
06361
06362
06363 int Dictionary::NumberOfElementsFilterAttributes(PropertyAttributes filter) {
06364 int capacity = Capacity();
06365 int result = 0;
06366 for (int i = 0; i < capacity; i++) {
06367 Object* k = KeyAt(i);
06368 if (IsKey(k)) {
06369 PropertyAttributes attr = DetailsAt(i).attributes();
06370 if ((attr & filter) == 0) result++;
06371 }
06372 }
06373 return result;
06374 }
06375
06376
06377 int Dictionary::NumberOfEnumElements() {
06378 return NumberOfElementsFilterAttributes(
06379 static_cast<PropertyAttributes>(DONT_ENUM));
06380 }
06381
06382
06383 void Dictionary::CopyKeysTo(FixedArray* storage, PropertyAttributes filter) {
06384 ASSERT(storage->length() >= NumberOfEnumElements());
06385 int capacity = Capacity();
06386 int index = 0;
06387 for (int i = 0; i < capacity; i++) {
06388 Object* k = KeyAt(i);
06389 if (IsKey(k)) {
06390 PropertyAttributes attr = DetailsAt(i).attributes();
06391 if ((attr & filter) == 0) storage->set(index++, k);
06392 }
06393 }
06394 ASSERT(storage->length() >= index);
06395 }
06396
06397
06398 void Dictionary::CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array) {
06399 ASSERT(storage->length() >= NumberOfEnumElements());
06400 int capacity = Capacity();
06401 int index = 0;
06402 for (int i = 0; i < capacity; i++) {
06403 Object* k = KeyAt(i);
06404 if (IsKey(k)) {
06405 PropertyDetails details = DetailsAt(i);
06406 if (!details.IsDontEnum()) {
06407 storage->set(index, k);
06408 sort_array->set(index,
06409 Smi::FromInt(details.index()),
06410 SKIP_WRITE_BARRIER);
06411 index++;
06412 }
06413 }
06414 }
06415 storage->SortPairs(sort_array);
06416 ASSERT(storage->length() >= index);
06417 }
06418
06419
06420 void Dictionary::CopyKeysTo(FixedArray* storage) {
06421 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
06422 static_cast<PropertyAttributes>(NONE)));
06423 int capacity = Capacity();
06424 int index = 0;
06425 for (int i = 0; i < capacity; i++) {
06426 Object* k = KeyAt(i);
06427 if (IsKey(k)) {
06428 storage->set(index++, k);
06429 }
06430 }
06431 ASSERT(storage->length() >= index);
06432 }
06433
06434
06435
06436 Object* Dictionary::SlowReverseLookup(Object* value) {
06437 int capacity = Capacity();
06438 for (int i = 0; i < capacity; i++) {
06439 Object* k = KeyAt(i);
06440 if (IsKey(k) && ValueAt(i) == value) {
06441 return k;
06442 }
06443 }
06444 return Heap::undefined_value();
06445 }
06446
06447
06448 Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj,
06449 int unused_property_fields) {
06450
06451
06452 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
06453
06454
06455 int max_enumeration_index =
06456 NextEnumerationIndex() +
06457 (DescriptorArray::kMaxNumberOfDescriptors - NumberOfElements());
06458 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
06459 Object* result = GenerateNewEnumerationIndices();
06460 if (result->IsFailure()) return result;
06461 }
06462
06463 int instance_descriptor_length = 0;
06464 int number_of_fields = 0;
06465
06466
06467 int capacity = Capacity();
06468 for (int i = 0; i < capacity; i++) {
06469 Object* k = KeyAt(i);
06470 if (IsKey(k)) {
06471 Object* value = ValueAt(i);
06472 PropertyType type = DetailsAt(i).type();
06473 ASSERT(type != FIELD);
06474 instance_descriptor_length++;
06475 if (type == NORMAL && !value->IsJSFunction()) number_of_fields += 1;
06476 }
06477 }
06478
06479
06480 Object* descriptors_unchecked =
06481 DescriptorArray::Allocate(instance_descriptor_length);
06482 if (descriptors_unchecked->IsFailure()) return descriptors_unchecked;
06483 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
06484
06485 int number_of_allocated_fields = number_of_fields + unused_property_fields;
06486
06487
06488 Object* fields = Heap::AllocateFixedArray(number_of_allocated_fields);
06489 if (fields->IsFailure()) return fields;
06490
06491
06492 DescriptorWriter w(descriptors);
06493 int current_offset = 0;
06494 for (int i = 0; i < capacity; i++) {
06495 Object* k = KeyAt(i);
06496 if (IsKey(k)) {
06497 Object* value = ValueAt(i);
06498
06499 Object* key = Heap::LookupSymbol(String::cast(k));
06500 if (key->IsFailure()) return key;
06501 PropertyDetails details = DetailsAt(i);
06502 PropertyType type = details.type();
06503 if (value->IsJSFunction()) {
06504 ConstantFunctionDescriptor d(String::cast(key),
06505 JSFunction::cast(value),
06506 details.attributes(),
06507 details.index());
06508 w.Write(&d);
06509 } else if (type == NORMAL) {
06510 FixedArray::cast(fields)->set(current_offset, value);
06511 FieldDescriptor d(String::cast(key),
06512 current_offset++,
06513 details.attributes(),
06514 details.index());
06515 w.Write(&d);
06516 } else if (type == CALLBACKS) {
06517 CallbacksDescriptor d(String::cast(key),
06518 value,
06519 details.attributes(),
06520 details.index());
06521 w.Write(&d);
06522 } else {
06523 UNREACHABLE();
06524 }
06525 }
06526 }
06527 ASSERT(current_offset == number_of_fields);
06528
06529 descriptors->Sort();
06530
06531 Object* new_map = obj->map()->Copy();
06532 if (new_map->IsFailure()) return new_map;
06533
06534
06535 obj->set_map(Map::cast(new_map));
06536 obj->map()->set_instance_descriptors(descriptors);
06537 obj->map()->set_unused_property_fields(unused_property_fields);
06538
06539 obj->set_properties(FixedArray::cast(fields));
06540 ASSERT(obj->IsJSObject());
06541
06542 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
06543
06544 ASSERT(obj->HasFastProperties());
06545 return obj;
06546 }
06547
06548
06549
06550 bool DebugInfo::HasBreakPoint(int code_position) {
06551
06552 Object* break_point_info = GetBreakPointInfo(code_position);
06553
06554
06555
06556 if (break_point_info->IsUndefined()) return false;
06557 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
06558 }
06559
06560
06561
06562 Object* DebugInfo::GetBreakPointInfo(int code_position) {
06563
06564 int index = GetBreakPointInfoIndex(code_position);
06565
06566
06567 if (index == kNoBreakPointInfo) return Heap::undefined_value();
06568 return BreakPointInfo::cast(break_points()->get(index));
06569 }
06570
06571
06572
06573 void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
06574 int code_position,
06575 Handle<Object> break_point_object) {
06576 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
06577 if (break_point_info->IsUndefined()) return;
06578 BreakPointInfo::ClearBreakPoint(
06579 Handle<BreakPointInfo>::cast(break_point_info),
06580 break_point_object);
06581 }
06582
06583
06584 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
06585 int code_position,
06586 int source_position,
06587 int statement_position,
06588 Handle<Object> break_point_object) {
06589 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
06590 if (!break_point_info->IsUndefined()) {
06591 BreakPointInfo::SetBreakPoint(
06592 Handle<BreakPointInfo>::cast(break_point_info),
06593 break_point_object);
06594 return;
06595 }
06596
06597
06598
06599 int index = kNoBreakPointInfo;
06600 for (int i = 0; i < debug_info->break_points()->length(); i++) {
06601 if (debug_info->break_points()->get(i)->IsUndefined()) {
06602 index = i;
06603 break;
06604 }
06605 }
06606 if (index == kNoBreakPointInfo) {
06607
06608 Handle<FixedArray> old_break_points =
06609 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
06610 debug_info->set_break_points(*Factory::NewFixedArray(
06611 old_break_points->length() +
06612 Debug::kEstimatedNofBreakPointsInFunction));
06613 Handle<FixedArray> new_break_points =
06614 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
06615 for (int i = 0; i < old_break_points->length(); i++) {
06616 new_break_points->set(i, old_break_points->get(i));
06617 }
06618 index = old_break_points->length();
06619 }
06620 ASSERT(index != kNoBreakPointInfo);
06621
06622
06623 Handle<BreakPointInfo> new_break_point_info =
06624 Handle<BreakPointInfo>::cast(Factory::NewStruct(BREAK_POINT_INFO_TYPE));
06625 new_break_point_info->set_code_position(Smi::FromInt(code_position));
06626 new_break_point_info->set_source_position(Smi::FromInt(source_position));
06627 new_break_point_info->
06628 set_statement_position(Smi::FromInt(statement_position));
06629 new_break_point_info->set_break_point_objects(Heap::undefined_value());
06630 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
06631 debug_info->break_points()->set(index, *new_break_point_info);
06632 }
06633
06634
06635
06636 Object* DebugInfo::GetBreakPointObjects(int code_position) {
06637 Object* break_point_info = GetBreakPointInfo(code_position);
06638 if (break_point_info->IsUndefined()) {
06639 return Heap::undefined_value();
06640 }
06641 return BreakPointInfo::cast(break_point_info)->break_point_objects();
06642 }
06643
06644
06645
06646 int DebugInfo::GetBreakPointCount() {
06647 if (break_points()->IsUndefined()) return 0;
06648 int count = 0;
06649 for (int i = 0; i < break_points()->length(); i++) {
06650 if (!break_points()->get(i)->IsUndefined()) {
06651 BreakPointInfo* break_point_info =
06652 BreakPointInfo::cast(break_points()->get(i));
06653 count += break_point_info->GetBreakPointCount();
06654 }
06655 }
06656 return count;
06657 }
06658
06659
06660 Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
06661 Handle<Object> break_point_object) {
06662 if (debug_info->break_points()->IsUndefined()) return Heap::undefined_value();
06663 for (int i = 0; i < debug_info->break_points()->length(); i++) {
06664 if (!debug_info->break_points()->get(i)->IsUndefined()) {
06665 Handle<BreakPointInfo> break_point_info =
06666 Handle<BreakPointInfo>(BreakPointInfo::cast(
06667 debug_info->break_points()->get(i)));
06668 if (BreakPointInfo::HasBreakPointObject(break_point_info,
06669 break_point_object)) {
06670 return *break_point_info;
06671 }
06672 }
06673 }
06674 return Heap::undefined_value();
06675 }
06676
06677
06678
06679
06680 int DebugInfo::GetBreakPointInfoIndex(int code_position) {
06681 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
06682 for (int i = 0; i < break_points()->length(); i++) {
06683 if (!break_points()->get(i)->IsUndefined()) {
06684 BreakPointInfo* break_point_info =
06685 BreakPointInfo::cast(break_points()->get(i));
06686 if (break_point_info->code_position()->value() == code_position) {
06687 return i;
06688 }
06689 }
06690 }
06691 return kNoBreakPointInfo;
06692 }
06693
06694
06695
06696 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
06697 Handle<Object> break_point_object) {
06698
06699 if (break_point_info->break_point_objects()->IsUndefined()) return;
06700
06701 if (!break_point_info->break_point_objects()->IsFixedArray()) {
06702 if (break_point_info->break_point_objects() == *break_point_object) {
06703 break_point_info->set_break_point_objects(Heap::undefined_value());
06704 }
06705 return;
06706 }
06707
06708 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
06709 Handle<FixedArray> old_array =
06710 Handle<FixedArray>(
06711 FixedArray::cast(break_point_info->break_point_objects()));
06712 Handle<FixedArray> new_array =
06713 Factory::NewFixedArray(old_array->length() - 1);
06714 int found_count = 0;
06715 for (int i = 0; i < old_array->length(); i++) {
06716 if (old_array->get(i) == *break_point_object) {
06717 ASSERT(found_count == 0);
06718 found_count++;
06719 } else {
06720 new_array->set(i - found_count, old_array->get(i));
06721 }
06722 }
06723
06724 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
06725 }
06726
06727
06728
06729 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
06730 Handle<Object> break_point_object) {
06731
06732 if (break_point_info->break_point_objects()->IsUndefined()) {
06733 break_point_info->set_break_point_objects(*break_point_object);
06734 return;
06735 }
06736
06737 if (break_point_info->break_point_objects() == *break_point_object) return;
06738
06739 if (!break_point_info->break_point_objects()->IsFixedArray()) {
06740 Handle<FixedArray> array = Factory::NewFixedArray(2);
06741 array->set(0, break_point_info->break_point_objects());
06742 array->set(1, *break_point_object);
06743 break_point_info->set_break_point_objects(*array);
06744 return;
06745 }
06746
06747 Handle<FixedArray> old_array =
06748 Handle<FixedArray>(
06749 FixedArray::cast(break_point_info->break_point_objects()));
06750 Handle<FixedArray> new_array =
06751 Factory::NewFixedArray(old_array->length() + 1);
06752 for (int i = 0; i < old_array->length(); i++) {
06753
06754 if (old_array->get(i) == *break_point_object) return;
06755 new_array->set(i, old_array->get(i));
06756 }
06757
06758 new_array->set(old_array->length(), *break_point_object);
06759 break_point_info->set_break_point_objects(*new_array);
06760 }
06761
06762
06763 bool BreakPointInfo::HasBreakPointObject(
06764 Handle<BreakPointInfo> break_point_info,
06765 Handle<Object> break_point_object) {
06766
06767 if (break_point_info->break_point_objects()->IsUndefined()) return false;
06768
06769 if (!break_point_info->break_point_objects()->IsFixedArray()) {
06770 return break_point_info->break_point_objects() == *break_point_object;
06771 }
06772
06773 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
06774 for (int i = 0; i < array->length(); i++) {
06775 if (array->get(i) == *break_point_object) {
06776 return true;
06777 }
06778 }
06779 return false;
06780 }
06781
06782
06783
06784 int BreakPointInfo::GetBreakPointCount() {
06785
06786 if (break_point_objects()->IsUndefined()) return 0;
06787
06788 if (!break_point_objects()->IsFixedArray()) return 1;
06789
06790 return FixedArray::cast(break_point_objects())->length();
06791 }
06792
06793
06794 } }