runtime.cc revision 25f6136652d8341ed047e7fc1a450af5bd218ea9
1// Copyright 2006-2009 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <stdlib.h> 29 30#include "v8.h" 31 32#include "accessors.h" 33#include "api.h" 34#include "arguments.h" 35#include "codegen.h" 36#include "compiler.h" 37#include "cpu.h" 38#include "dateparser-inl.h" 39#include "debug.h" 40#include "execution.h" 41#include "jsregexp.h" 42#include "liveedit.h" 43#include "parser.h" 44#include "platform.h" 45#include "runtime.h" 46#include "scopeinfo.h" 47#include "smart-pointer.h" 48#include "stub-cache.h" 49#include "v8threads.h" 50 51namespace v8 { 52namespace internal { 53 54 55#define RUNTIME_ASSERT(value) \ 56 if (!(value)) return Top::ThrowIllegalOperation(); 57 58// Cast the given object to a value of the specified type and store 59// it in a variable with the given name. If the object is not of the 60// expected type call IllegalOperation and return. 61#define CONVERT_CHECKED(Type, name, obj) \ 62 RUNTIME_ASSERT(obj->Is##Type()); \ 63 Type* name = Type::cast(obj); 64 65#define CONVERT_ARG_CHECKED(Type, name, index) \ 66 RUNTIME_ASSERT(args[index]->Is##Type()); \ 67 Handle<Type> name = args.at<Type>(index); 68 69// Cast the given object to a boolean and store it in a variable with 70// the given name. If the object is not a boolean call IllegalOperation 71// and return. 72#define CONVERT_BOOLEAN_CHECKED(name, obj) \ 73 RUNTIME_ASSERT(obj->IsBoolean()); \ 74 bool name = (obj)->IsTrue(); 75 76// Cast the given object to a Smi and store its value in an int variable 77// with the given name. If the object is not a Smi call IllegalOperation 78// and return. 79#define CONVERT_SMI_CHECKED(name, obj) \ 80 RUNTIME_ASSERT(obj->IsSmi()); \ 81 int name = Smi::cast(obj)->value(); 82 83// Cast the given object to a double and store it in a variable with 84// the given name. If the object is not a number (as opposed to 85// the number not-a-number) call IllegalOperation and return. 86#define CONVERT_DOUBLE_CHECKED(name, obj) \ 87 RUNTIME_ASSERT(obj->IsNumber()); \ 88 double name = (obj)->Number(); 89 90// Call the specified converter on the object *comand store the result in 91// a variable of the specified type with the given name. If the 92// object is not a Number call IllegalOperation and return. 93#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ 94 RUNTIME_ASSERT(obj->IsNumber()); \ 95 type name = NumberTo##Type(obj); 96 97// Non-reentrant string buffer for efficient general use in this file. 98static StaticResource<StringInputBuffer> runtime_string_input_buffer; 99 100 101static Object* DeepCopyBoilerplate(JSObject* boilerplate) { 102 StackLimitCheck check; 103 if (check.HasOverflowed()) return Top::StackOverflow(); 104 105 Object* result = Heap::CopyJSObject(boilerplate); 106 if (result->IsFailure()) return result; 107 JSObject* copy = JSObject::cast(result); 108 109 // Deep copy local properties. 110 if (copy->HasFastProperties()) { 111 FixedArray* properties = copy->properties(); 112 for (int i = 0; i < properties->length(); i++) { 113 Object* value = properties->get(i); 114 if (value->IsJSObject()) { 115 JSObject* js_object = JSObject::cast(value); 116 result = DeepCopyBoilerplate(js_object); 117 if (result->IsFailure()) return result; 118 properties->set(i, result); 119 } 120 } 121 int nof = copy->map()->inobject_properties(); 122 for (int i = 0; i < nof; i++) { 123 Object* value = copy->InObjectPropertyAt(i); 124 if (value->IsJSObject()) { 125 JSObject* js_object = JSObject::cast(value); 126 result = DeepCopyBoilerplate(js_object); 127 if (result->IsFailure()) return result; 128 copy->InObjectPropertyAtPut(i, result); 129 } 130 } 131 } else { 132 result = Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE)); 133 if (result->IsFailure()) return result; 134 FixedArray* names = FixedArray::cast(result); 135 copy->GetLocalPropertyNames(names, 0); 136 for (int i = 0; i < names->length(); i++) { 137 ASSERT(names->get(i)->IsString()); 138 String* key_string = String::cast(names->get(i)); 139 PropertyAttributes attributes = 140 copy->GetLocalPropertyAttribute(key_string); 141 // Only deep copy fields from the object literal expression. 142 // In particular, don't try to copy the length attribute of 143 // an array. 144 if (attributes != NONE) continue; 145 Object* value = copy->GetProperty(key_string, &attributes); 146 ASSERT(!value->IsFailure()); 147 if (value->IsJSObject()) { 148 JSObject* js_object = JSObject::cast(value); 149 result = DeepCopyBoilerplate(js_object); 150 if (result->IsFailure()) return result; 151 result = copy->SetProperty(key_string, result, NONE); 152 if (result->IsFailure()) return result; 153 } 154 } 155 } 156 157 // Deep copy local elements. 158 // Pixel elements cannot be created using an object literal. 159 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements()); 160 switch (copy->GetElementsKind()) { 161 case JSObject::FAST_ELEMENTS: { 162 FixedArray* elements = FixedArray::cast(copy->elements()); 163 for (int i = 0; i < elements->length(); i++) { 164 Object* value = elements->get(i); 165 if (value->IsJSObject()) { 166 JSObject* js_object = JSObject::cast(value); 167 result = DeepCopyBoilerplate(js_object); 168 if (result->IsFailure()) return result; 169 elements->set(i, result); 170 } 171 } 172 break; 173 } 174 case JSObject::DICTIONARY_ELEMENTS: { 175 NumberDictionary* element_dictionary = copy->element_dictionary(); 176 int capacity = element_dictionary->Capacity(); 177 for (int i = 0; i < capacity; i++) { 178 Object* k = element_dictionary->KeyAt(i); 179 if (element_dictionary->IsKey(k)) { 180 Object* value = element_dictionary->ValueAt(i); 181 if (value->IsJSObject()) { 182 JSObject* js_object = JSObject::cast(value); 183 result = DeepCopyBoilerplate(js_object); 184 if (result->IsFailure()) return result; 185 element_dictionary->ValueAtPut(i, result); 186 } 187 } 188 } 189 break; 190 } 191 default: 192 UNREACHABLE(); 193 break; 194 } 195 return copy; 196} 197 198 199static Object* Runtime_CloneLiteralBoilerplate(Arguments args) { 200 CONVERT_CHECKED(JSObject, boilerplate, args[0]); 201 return DeepCopyBoilerplate(boilerplate); 202} 203 204 205static Object* Runtime_CloneShallowLiteralBoilerplate(Arguments args) { 206 CONVERT_CHECKED(JSObject, boilerplate, args[0]); 207 return Heap::CopyJSObject(boilerplate); 208} 209 210 211static Handle<Map> ComputeObjectLiteralMap( 212 Handle<Context> context, 213 Handle<FixedArray> constant_properties, 214 bool* is_result_from_cache) { 215 int number_of_properties = constant_properties->length() / 2; 216 if (FLAG_canonicalize_object_literal_maps) { 217 // First find prefix of consecutive symbol keys. 218 int number_of_symbol_keys = 0; 219 while ((number_of_symbol_keys < number_of_properties) && 220 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) { 221 number_of_symbol_keys++; 222 } 223 // Based on the number of prefix symbols key we decide whether 224 // to use the map cache in the global context. 225 const int kMaxKeys = 10; 226 if ((number_of_symbol_keys == number_of_properties) && 227 (number_of_symbol_keys < kMaxKeys)) { 228 // Create the fixed array with the key. 229 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys); 230 for (int i = 0; i < number_of_symbol_keys; i++) { 231 keys->set(i, constant_properties->get(i*2)); 232 } 233 *is_result_from_cache = true; 234 return Factory::ObjectLiteralMapFromCache(context, keys); 235 } 236 } 237 *is_result_from_cache = false; 238 return Factory::CopyMap( 239 Handle<Map>(context->object_function()->initial_map()), 240 number_of_properties); 241} 242 243 244static Handle<Object> CreateLiteralBoilerplate( 245 Handle<FixedArray> literals, 246 Handle<FixedArray> constant_properties); 247 248 249static Handle<Object> CreateObjectLiteralBoilerplate( 250 Handle<FixedArray> literals, 251 Handle<FixedArray> constant_properties, 252 bool should_have_fast_elements) { 253 // Get the global context from the literals array. This is the 254 // context in which the function was created and we use the object 255 // function from this context to create the object literal. We do 256 // not use the object function from the current global context 257 // because this might be the object function from another context 258 // which we should not have access to. 259 Handle<Context> context = 260 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); 261 262 bool is_result_from_cache; 263 Handle<Map> map = ComputeObjectLiteralMap(context, 264 constant_properties, 265 &is_result_from_cache); 266 267 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); 268 269 // Normalize the elements of the boilerplate to save space if needed. 270 if (!should_have_fast_elements) NormalizeElements(boilerplate); 271 272 { // Add the constant properties to the boilerplate. 273 int length = constant_properties->length(); 274 OptimizedObjectForAddingMultipleProperties opt(boilerplate, 275 length / 2, 276 !is_result_from_cache); 277 for (int index = 0; index < length; index +=2) { 278 Handle<Object> key(constant_properties->get(index+0)); 279 Handle<Object> value(constant_properties->get(index+1)); 280 if (value->IsFixedArray()) { 281 // The value contains the constant_properties of a 282 // simple object literal. 283 Handle<FixedArray> array = Handle<FixedArray>::cast(value); 284 value = CreateLiteralBoilerplate(literals, array); 285 if (value.is_null()) return value; 286 } 287 Handle<Object> result; 288 uint32_t element_index = 0; 289 if (key->IsSymbol()) { 290 // If key is a symbol it is not an array element. 291 Handle<String> name(String::cast(*key)); 292 ASSERT(!name->AsArrayIndex(&element_index)); 293 result = SetProperty(boilerplate, name, value, NONE); 294 } else if (Array::IndexFromObject(*key, &element_index)) { 295 // Array index (uint32). 296 result = SetElement(boilerplate, element_index, value); 297 } else { 298 // Non-uint32 number. 299 ASSERT(key->IsNumber()); 300 double num = key->Number(); 301 char arr[100]; 302 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 303 const char* str = DoubleToCString(num, buffer); 304 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); 305 result = SetProperty(boilerplate, name, value, NONE); 306 } 307 // If setting the property on the boilerplate throws an 308 // exception, the exception is converted to an empty handle in 309 // the handle based operations. In that case, we need to 310 // convert back to an exception. 311 if (result.is_null()) return result; 312 } 313 } 314 315 return boilerplate; 316} 317 318 319static Handle<Object> CreateArrayLiteralBoilerplate( 320 Handle<FixedArray> literals, 321 Handle<FixedArray> elements) { 322 // Create the JSArray. 323 Handle<JSFunction> constructor( 324 JSFunction::GlobalContextFromLiterals(*literals)->array_function()); 325 Handle<Object> object = Factory::NewJSObject(constructor); 326 327 Handle<Object> copied_elements = Factory::CopyFixedArray(elements); 328 329 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements); 330 for (int i = 0; i < content->length(); i++) { 331 if (content->get(i)->IsFixedArray()) { 332 // The value contains the constant_properties of a 333 // simple object literal. 334 Handle<FixedArray> fa(FixedArray::cast(content->get(i))); 335 Handle<Object> result = 336 CreateLiteralBoilerplate(literals, fa); 337 if (result.is_null()) return result; 338 content->set(i, *result); 339 } 340 } 341 342 // Set the elements. 343 Handle<JSArray>::cast(object)->SetContent(*content); 344 return object; 345} 346 347 348static Handle<Object> CreateLiteralBoilerplate( 349 Handle<FixedArray> literals, 350 Handle<FixedArray> array) { 351 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); 352 switch (CompileTimeValue::GetType(array)) { 353 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: 354 return CreateObjectLiteralBoilerplate(literals, elements, true); 355 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: 356 return CreateObjectLiteralBoilerplate(literals, elements, false); 357 case CompileTimeValue::ARRAY_LITERAL: 358 return CreateArrayLiteralBoilerplate(literals, elements); 359 default: 360 UNREACHABLE(); 361 return Handle<Object>::null(); 362 } 363} 364 365 366static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { 367 // Takes a FixedArray of elements containing the literal elements of 368 // the array literal and produces JSArray with those elements. 369 // Additionally takes the literals array of the surrounding function 370 // which contains the context from which to get the Array function 371 // to use for creating the array literal. 372 HandleScope scope; 373 ASSERT(args.length() == 3); 374 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 375 CONVERT_SMI_CHECKED(literals_index, args[1]); 376 CONVERT_ARG_CHECKED(FixedArray, elements, 2); 377 378 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements); 379 if (object.is_null()) return Failure::Exception(); 380 381 // Update the functions literal and return the boilerplate. 382 literals->set(literals_index, *object); 383 return *object; 384} 385 386 387static Object* Runtime_CreateObjectLiteral(Arguments args) { 388 HandleScope scope; 389 ASSERT(args.length() == 4); 390 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 391 CONVERT_SMI_CHECKED(literals_index, args[1]); 392 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); 393 CONVERT_SMI_CHECKED(fast_elements, args[3]); 394 bool should_have_fast_elements = fast_elements == 1; 395 396 // Check if boilerplate exists. If not, create it first. 397 Handle<Object> boilerplate(literals->get(literals_index)); 398 if (*boilerplate == Heap::undefined_value()) { 399 boilerplate = CreateObjectLiteralBoilerplate(literals, 400 constant_properties, 401 should_have_fast_elements); 402 if (boilerplate.is_null()) return Failure::Exception(); 403 // Update the functions literal and return the boilerplate. 404 literals->set(literals_index, *boilerplate); 405 } 406 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); 407} 408 409 410static Object* Runtime_CreateObjectLiteralShallow(Arguments args) { 411 HandleScope scope; 412 ASSERT(args.length() == 4); 413 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 414 CONVERT_SMI_CHECKED(literals_index, args[1]); 415 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); 416 CONVERT_SMI_CHECKED(fast_elements, args[3]); 417 bool should_have_fast_elements = fast_elements == 1; 418 419 // Check if boilerplate exists. If not, create it first. 420 Handle<Object> boilerplate(literals->get(literals_index)); 421 if (*boilerplate == Heap::undefined_value()) { 422 boilerplate = CreateObjectLiteralBoilerplate(literals, 423 constant_properties, 424 should_have_fast_elements); 425 if (boilerplate.is_null()) return Failure::Exception(); 426 // Update the functions literal and return the boilerplate. 427 literals->set(literals_index, *boilerplate); 428 } 429 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); 430} 431 432 433static Object* Runtime_CreateArrayLiteral(Arguments args) { 434 HandleScope scope; 435 ASSERT(args.length() == 3); 436 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 437 CONVERT_SMI_CHECKED(literals_index, args[1]); 438 CONVERT_ARG_CHECKED(FixedArray, elements, 2); 439 440 // Check if boilerplate exists. If not, create it first. 441 Handle<Object> boilerplate(literals->get(literals_index)); 442 if (*boilerplate == Heap::undefined_value()) { 443 boilerplate = CreateArrayLiteralBoilerplate(literals, elements); 444 if (boilerplate.is_null()) return Failure::Exception(); 445 // Update the functions literal and return the boilerplate. 446 literals->set(literals_index, *boilerplate); 447 } 448 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); 449} 450 451 452static Object* Runtime_CreateArrayLiteralShallow(Arguments args) { 453 HandleScope scope; 454 ASSERT(args.length() == 3); 455 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 456 CONVERT_SMI_CHECKED(literals_index, args[1]); 457 CONVERT_ARG_CHECKED(FixedArray, elements, 2); 458 459 // Check if boilerplate exists. If not, create it first. 460 Handle<Object> boilerplate(literals->get(literals_index)); 461 if (*boilerplate == Heap::undefined_value()) { 462 boilerplate = CreateArrayLiteralBoilerplate(literals, elements); 463 if (boilerplate.is_null()) return Failure::Exception(); 464 // Update the functions literal and return the boilerplate. 465 literals->set(literals_index, *boilerplate); 466 } 467 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); 468} 469 470 471static Object* Runtime_CreateCatchExtensionObject(Arguments args) { 472 ASSERT(args.length() == 2); 473 CONVERT_CHECKED(String, key, args[0]); 474 Object* value = args[1]; 475 // Create a catch context extension object. 476 JSFunction* constructor = 477 Top::context()->global_context()->context_extension_function(); 478 Object* object = Heap::AllocateJSObject(constructor); 479 if (object->IsFailure()) return object; 480 // Assign the exception value to the catch variable and make sure 481 // that the catch variable is DontDelete. 482 value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE); 483 if (value->IsFailure()) return value; 484 return object; 485} 486 487 488static Object* Runtime_ClassOf(Arguments args) { 489 NoHandleAllocation ha; 490 ASSERT(args.length() == 1); 491 Object* obj = args[0]; 492 if (!obj->IsJSObject()) return Heap::null_value(); 493 return JSObject::cast(obj)->class_name(); 494} 495 496 497static Object* Runtime_IsInPrototypeChain(Arguments args) { 498 NoHandleAllocation ha; 499 ASSERT(args.length() == 2); 500 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). 501 Object* O = args[0]; 502 Object* V = args[1]; 503 while (true) { 504 Object* prototype = V->GetPrototype(); 505 if (prototype->IsNull()) return Heap::false_value(); 506 if (O == prototype) return Heap::true_value(); 507 V = prototype; 508 } 509} 510 511 512// Inserts an object as the hidden prototype of another object. 513static Object* Runtime_SetHiddenPrototype(Arguments args) { 514 NoHandleAllocation ha; 515 ASSERT(args.length() == 2); 516 CONVERT_CHECKED(JSObject, jsobject, args[0]); 517 CONVERT_CHECKED(JSObject, proto, args[1]); 518 519 // Sanity checks. The old prototype (that we are replacing) could 520 // theoretically be null, but if it is not null then check that we 521 // didn't already install a hidden prototype here. 522 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() || 523 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype()); 524 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype()); 525 526 // Allocate up front before we start altering state in case we get a GC. 527 Object* map_or_failure = proto->map()->CopyDropTransitions(); 528 if (map_or_failure->IsFailure()) return map_or_failure; 529 Map* new_proto_map = Map::cast(map_or_failure); 530 531 map_or_failure = jsobject->map()->CopyDropTransitions(); 532 if (map_or_failure->IsFailure()) return map_or_failure; 533 Map* new_map = Map::cast(map_or_failure); 534 535 // Set proto's prototype to be the old prototype of the object. 536 new_proto_map->set_prototype(jsobject->GetPrototype()); 537 proto->set_map(new_proto_map); 538 new_proto_map->set_is_hidden_prototype(); 539 540 // Set the object's prototype to proto. 541 new_map->set_prototype(proto); 542 jsobject->set_map(new_map); 543 544 return Heap::undefined_value(); 545} 546 547 548static Object* Runtime_IsConstructCall(Arguments args) { 549 NoHandleAllocation ha; 550 ASSERT(args.length() == 0); 551 JavaScriptFrameIterator it; 552 return Heap::ToBoolean(it.frame()->IsConstructor()); 553} 554 555 556// Recursively traverses hidden prototypes if property is not found 557static void GetOwnPropertyImplementation(JSObject* obj, 558 String* name, 559 LookupResult* result) { 560 obj->LocalLookupRealNamedProperty(name, result); 561 562 if (!result->IsProperty()) { 563 Object* proto = obj->GetPrototype(); 564 if (proto->IsJSObject() && 565 JSObject::cast(proto)->map()->is_hidden_prototype()) 566 GetOwnPropertyImplementation(JSObject::cast(proto), 567 name, result); 568 } 569} 570 571 572// Returns an array with the property description: 573// if args[1] is not a property on args[0] 574// returns undefined 575// if args[1] is a data property on args[0] 576// [false, value, Writeable, Enumerable, Configurable] 577// if args[1] is an accessor on args[0] 578// [true, GetFunction, SetFunction, Enumerable, Configurable] 579static Object* Runtime_GetOwnProperty(Arguments args) { 580 ASSERT(args.length() == 2); 581 HandleScope scope; 582 Handle<FixedArray> elms = Factory::NewFixedArray(5); 583 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms); 584 LookupResult result; 585 CONVERT_CHECKED(JSObject, obj, args[0]); 586 CONVERT_CHECKED(String, name, args[1]); 587 588 // Use recursive implementation to also traverse hidden prototypes 589 GetOwnPropertyImplementation(obj, name, &result); 590 591 if (!result.IsProperty()) 592 return Heap::undefined_value(); 593 594 if (result.type() == CALLBACKS) { 595 Object* structure = result.GetCallbackObject(); 596 if (structure->IsProxy() || structure->IsAccessorInfo()) { 597 // Property that is internally implemented as a callback or 598 // an API defined callback. 599 Object* value = obj->GetPropertyWithCallback( 600 obj, structure, name, result.holder()); 601 elms->set(0, Heap::false_value()); 602 elms->set(1, value); 603 elms->set(2, Heap::ToBoolean(!result.IsReadOnly())); 604 } else if (structure->IsFixedArray()) { 605 // __defineGetter__/__defineSetter__ callback. 606 elms->set(0, Heap::true_value()); 607 elms->set(1, FixedArray::cast(structure)->get(0)); 608 elms->set(2, FixedArray::cast(structure)->get(1)); 609 } else { 610 return Heap::undefined_value(); 611 } 612 } else { 613 elms->set(0, Heap::false_value()); 614 elms->set(1, result.GetLazyValue()); 615 elms->set(2, Heap::ToBoolean(!result.IsReadOnly())); 616 } 617 618 elms->set(3, Heap::ToBoolean(!result.IsDontEnum())); 619 elms->set(4, Heap::ToBoolean(!result.IsDontDelete())); 620 return *desc; 621} 622 623 624static Object* Runtime_IsExtensible(Arguments args) { 625 ASSERT(args.length() == 1); 626 CONVERT_CHECKED(JSObject, obj, args[0]); 627 return obj->map()->is_extensible() ? Heap::true_value() 628 : Heap::false_value(); 629} 630 631 632static Object* Runtime_RegExpCompile(Arguments args) { 633 HandleScope scope; 634 ASSERT(args.length() == 3); 635 CONVERT_ARG_CHECKED(JSRegExp, re, 0); 636 CONVERT_ARG_CHECKED(String, pattern, 1); 637 CONVERT_ARG_CHECKED(String, flags, 2); 638 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags); 639 if (result.is_null()) return Failure::Exception(); 640 return *result; 641} 642 643 644static Object* Runtime_CreateApiFunction(Arguments args) { 645 HandleScope scope; 646 ASSERT(args.length() == 1); 647 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0); 648 return *Factory::CreateApiFunction(data); 649} 650 651 652static Object* Runtime_IsTemplate(Arguments args) { 653 ASSERT(args.length() == 1); 654 Object* arg = args[0]; 655 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); 656 return Heap::ToBoolean(result); 657} 658 659 660static Object* Runtime_GetTemplateField(Arguments args) { 661 ASSERT(args.length() == 2); 662 CONVERT_CHECKED(HeapObject, templ, args[0]); 663 CONVERT_CHECKED(Smi, field, args[1]); 664 int index = field->value(); 665 int offset = index * kPointerSize + HeapObject::kHeaderSize; 666 InstanceType type = templ->map()->instance_type(); 667 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || 668 type == OBJECT_TEMPLATE_INFO_TYPE); 669 RUNTIME_ASSERT(offset > 0); 670 if (type == FUNCTION_TEMPLATE_INFO_TYPE) { 671 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); 672 } else { 673 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); 674 } 675 return *HeapObject::RawField(templ, offset); 676} 677 678 679static Object* Runtime_DisableAccessChecks(Arguments args) { 680 ASSERT(args.length() == 1); 681 CONVERT_CHECKED(HeapObject, object, args[0]); 682 Map* old_map = object->map(); 683 bool needs_access_checks = old_map->is_access_check_needed(); 684 if (needs_access_checks) { 685 // Copy map so it won't interfere constructor's initial map. 686 Object* new_map = old_map->CopyDropTransitions(); 687 if (new_map->IsFailure()) return new_map; 688 689 Map::cast(new_map)->set_is_access_check_needed(false); 690 object->set_map(Map::cast(new_map)); 691 } 692 return needs_access_checks ? Heap::true_value() : Heap::false_value(); 693} 694 695 696static Object* Runtime_EnableAccessChecks(Arguments args) { 697 ASSERT(args.length() == 1); 698 CONVERT_CHECKED(HeapObject, object, args[0]); 699 Map* old_map = object->map(); 700 if (!old_map->is_access_check_needed()) { 701 // Copy map so it won't interfere constructor's initial map. 702 Object* new_map = old_map->CopyDropTransitions(); 703 if (new_map->IsFailure()) return new_map; 704 705 Map::cast(new_map)->set_is_access_check_needed(true); 706 object->set_map(Map::cast(new_map)); 707 } 708 return Heap::undefined_value(); 709} 710 711 712static Object* ThrowRedeclarationError(const char* type, Handle<String> name) { 713 HandleScope scope; 714 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type)); 715 Handle<Object> args[2] = { type_handle, name }; 716 Handle<Object> error = 717 Factory::NewTypeError("redeclaration", HandleVector(args, 2)); 718 return Top::Throw(*error); 719} 720 721 722static Object* Runtime_DeclareGlobals(Arguments args) { 723 HandleScope scope; 724 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global()); 725 726 Handle<Context> context = args.at<Context>(0); 727 CONVERT_ARG_CHECKED(FixedArray, pairs, 1); 728 bool is_eval = Smi::cast(args[2])->value() == 1; 729 730 // Compute the property attributes. According to ECMA-262, section 731 // 13, page 71, the property must be read-only and 732 // non-deletable. However, neither SpiderMonkey nor KJS creates the 733 // property as read-only, so we don't either. 734 PropertyAttributes base = is_eval ? NONE : DONT_DELETE; 735 736 // Traverse the name/value pairs and set the properties. 737 int length = pairs->length(); 738 for (int i = 0; i < length; i += 2) { 739 HandleScope scope; 740 Handle<String> name(String::cast(pairs->get(i))); 741 Handle<Object> value(pairs->get(i + 1)); 742 743 // We have to declare a global const property. To capture we only 744 // assign to it when evaluating the assignment for "const x = 745 // <expr>" the initial value is the hole. 746 bool is_const_property = value->IsTheHole(); 747 748 if (value->IsUndefined() || is_const_property) { 749 // Lookup the property in the global object, and don't set the 750 // value of the variable if the property is already there. 751 LookupResult lookup; 752 global->Lookup(*name, &lookup); 753 if (lookup.IsProperty()) { 754 // Determine if the property is local by comparing the holder 755 // against the global object. The information will be used to 756 // avoid throwing re-declaration errors when declaring 757 // variables or constants that exist in the prototype chain. 758 bool is_local = (*global == lookup.holder()); 759 // Get the property attributes and determine if the property is 760 // read-only. 761 PropertyAttributes attributes = global->GetPropertyAttribute(*name); 762 bool is_read_only = (attributes & READ_ONLY) != 0; 763 if (lookup.type() == INTERCEPTOR) { 764 // If the interceptor says the property is there, we 765 // just return undefined without overwriting the property. 766 // Otherwise, we continue to setting the property. 767 if (attributes != ABSENT) { 768 // Check if the existing property conflicts with regards to const. 769 if (is_local && (is_read_only || is_const_property)) { 770 const char* type = (is_read_only) ? "const" : "var"; 771 return ThrowRedeclarationError(type, name); 772 }; 773 // The property already exists without conflicting: Go to 774 // the next declaration. 775 continue; 776 } 777 // Fall-through and introduce the absent property by using 778 // SetProperty. 779 } else { 780 if (is_local && (is_read_only || is_const_property)) { 781 const char* type = (is_read_only) ? "const" : "var"; 782 return ThrowRedeclarationError(type, name); 783 } 784 // The property already exists without conflicting: Go to 785 // the next declaration. 786 continue; 787 } 788 } 789 } else { 790 // Copy the function and update its context. Use it as value. 791 Handle<SharedFunctionInfo> shared = 792 Handle<SharedFunctionInfo>::cast(value); 793 Handle<JSFunction> function = 794 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED); 795 value = function; 796 } 797 798 LookupResult lookup; 799 global->LocalLookup(*name, &lookup); 800 801 PropertyAttributes attributes = is_const_property 802 ? static_cast<PropertyAttributes>(base | READ_ONLY) 803 : base; 804 805 if (lookup.IsProperty()) { 806 // There's a local property that we need to overwrite because 807 // we're either declaring a function or there's an interceptor 808 // that claims the property is absent. 809 810 // Check for conflicting re-declarations. We cannot have 811 // conflicting types in case of intercepted properties because 812 // they are absent. 813 if (lookup.type() != INTERCEPTOR && 814 (lookup.IsReadOnly() || is_const_property)) { 815 const char* type = (lookup.IsReadOnly()) ? "const" : "var"; 816 return ThrowRedeclarationError(type, name); 817 } 818 SetProperty(global, name, value, attributes); 819 } else { 820 // If a property with this name does not already exist on the 821 // global object add the property locally. We take special 822 // precautions to always add it as a local property even in case 823 // of callbacks in the prototype chain (this rules out using 824 // SetProperty). Also, we must use the handle-based version to 825 // avoid GC issues. 826 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes); 827 } 828 } 829 830 return Heap::undefined_value(); 831} 832 833 834static Object* Runtime_DeclareContextSlot(Arguments args) { 835 HandleScope scope; 836 ASSERT(args.length() == 4); 837 838 CONVERT_ARG_CHECKED(Context, context, 0); 839 Handle<String> name(String::cast(args[1])); 840 PropertyAttributes mode = 841 static_cast<PropertyAttributes>(Smi::cast(args[2])->value()); 842 ASSERT(mode == READ_ONLY || mode == NONE); 843 Handle<Object> initial_value(args[3]); 844 845 // Declarations are always done in the function context. 846 context = Handle<Context>(context->fcontext()); 847 848 int index; 849 PropertyAttributes attributes; 850 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 851 Handle<Object> holder = 852 context->Lookup(name, flags, &index, &attributes); 853 854 if (attributes != ABSENT) { 855 // The name was declared before; check for conflicting 856 // re-declarations: This is similar to the code in parser.cc in 857 // the AstBuildingParser::Declare function. 858 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { 859 // Functions are not read-only. 860 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); 861 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; 862 return ThrowRedeclarationError(type, name); 863 } 864 865 // Initialize it if necessary. 866 if (*initial_value != NULL) { 867 if (index >= 0) { 868 // The variable or constant context slot should always be in 869 // the function context or the arguments object. 870 if (holder->IsContext()) { 871 ASSERT(holder.is_identical_to(context)); 872 if (((attributes & READ_ONLY) == 0) || 873 context->get(index)->IsTheHole()) { 874 context->set(index, *initial_value); 875 } 876 } else { 877 Handle<JSObject>::cast(holder)->SetElement(index, *initial_value); 878 } 879 } else { 880 // Slow case: The property is not in the FixedArray part of the context. 881 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); 882 SetProperty(context_ext, name, initial_value, mode); 883 } 884 } 885 886 } else { 887 // The property is not in the function context. It needs to be 888 // "declared" in the function context's extension context, or in the 889 // global context. 890 Handle<JSObject> context_ext; 891 if (context->has_extension()) { 892 // The function context's extension context exists - use it. 893 context_ext = Handle<JSObject>(context->extension()); 894 } else { 895 // The function context's extension context does not exists - allocate 896 // it. 897 context_ext = Factory::NewJSObject(Top::context_extension_function()); 898 // And store it in the extension slot. 899 context->set_extension(*context_ext); 900 } 901 ASSERT(*context_ext != NULL); 902 903 // Declare the property by setting it to the initial value if provided, 904 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for 905 // constant declarations). 906 ASSERT(!context_ext->HasLocalProperty(*name)); 907 Handle<Object> value(Heap::undefined_value()); 908 if (*initial_value != NULL) value = initial_value; 909 SetProperty(context_ext, name, value, mode); 910 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode); 911 } 912 913 return Heap::undefined_value(); 914} 915 916 917static Object* Runtime_InitializeVarGlobal(Arguments args) { 918 NoHandleAllocation nha; 919 920 // Determine if we need to assign to the variable if it already 921 // exists (based on the number of arguments). 922 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 923 bool assign = args.length() == 2; 924 925 CONVERT_ARG_CHECKED(String, name, 0); 926 GlobalObject* global = Top::context()->global(); 927 928 // According to ECMA-262, section 12.2, page 62, the property must 929 // not be deletable. 930 PropertyAttributes attributes = DONT_DELETE; 931 932 // Lookup the property locally in the global object. If it isn't 933 // there, there is a property with this name in the prototype chain. 934 // We follow Safari and Firefox behavior and only set the property 935 // locally if there is an explicit initialization value that we have 936 // to assign to the property. When adding the property we take 937 // special precautions to always add it as a local property even in 938 // case of callbacks in the prototype chain (this rules out using 939 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for 940 // this. 941 // Note that objects can have hidden prototypes, so we need to traverse 942 // the whole chain of hidden prototypes to do a 'local' lookup. 943 JSObject* real_holder = global; 944 LookupResult lookup; 945 while (true) { 946 real_holder->LocalLookup(*name, &lookup); 947 if (lookup.IsProperty()) { 948 // Determine if this is a redeclaration of something read-only. 949 if (lookup.IsReadOnly()) { 950 // If we found readonly property on one of hidden prototypes, 951 // just shadow it. 952 if (real_holder != Top::context()->global()) break; 953 return ThrowRedeclarationError("const", name); 954 } 955 956 // Determine if this is a redeclaration of an intercepted read-only 957 // property and figure out if the property exists at all. 958 bool found = true; 959 PropertyType type = lookup.type(); 960 if (type == INTERCEPTOR) { 961 HandleScope handle_scope; 962 Handle<JSObject> holder(real_holder); 963 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name); 964 real_holder = *holder; 965 if (intercepted == ABSENT) { 966 // The interceptor claims the property isn't there. We need to 967 // make sure to introduce it. 968 found = false; 969 } else if ((intercepted & READ_ONLY) != 0) { 970 // The property is present, but read-only. Since we're trying to 971 // overwrite it with a variable declaration we must throw a 972 // re-declaration error. However if we found readonly property 973 // on one of hidden prototypes, just shadow it. 974 if (real_holder != Top::context()->global()) break; 975 return ThrowRedeclarationError("const", name); 976 } 977 } 978 979 if (found && !assign) { 980 // The global property is there and we're not assigning any value 981 // to it. Just return. 982 return Heap::undefined_value(); 983 } 984 985 // Assign the value (or undefined) to the property. 986 Object* value = (assign) ? args[1] : Heap::undefined_value(); 987 return real_holder->SetProperty(&lookup, *name, value, attributes); 988 } 989 990 Object* proto = real_holder->GetPrototype(); 991 if (!proto->IsJSObject()) 992 break; 993 994 if (!JSObject::cast(proto)->map()->is_hidden_prototype()) 995 break; 996 997 real_holder = JSObject::cast(proto); 998 } 999 1000 global = Top::context()->global(); 1001 if (assign) { 1002 return global->IgnoreAttributesAndSetLocalProperty(*name, 1003 args[1], 1004 attributes); 1005 } 1006 return Heap::undefined_value(); 1007} 1008 1009 1010static Object* Runtime_InitializeConstGlobal(Arguments args) { 1011 // All constants are declared with an initial value. The name 1012 // of the constant is the first argument and the initial value 1013 // is the second. 1014 RUNTIME_ASSERT(args.length() == 2); 1015 CONVERT_ARG_CHECKED(String, name, 0); 1016 Handle<Object> value = args.at<Object>(1); 1017 1018 // Get the current global object from top. 1019 GlobalObject* global = Top::context()->global(); 1020 1021 // According to ECMA-262, section 12.2, page 62, the property must 1022 // not be deletable. Since it's a const, it must be READ_ONLY too. 1023 PropertyAttributes attributes = 1024 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); 1025 1026 // Lookup the property locally in the global object. If it isn't 1027 // there, we add the property and take special precautions to always 1028 // add it as a local property even in case of callbacks in the 1029 // prototype chain (this rules out using SetProperty). 1030 // We use IgnoreAttributesAndSetLocalProperty instead 1031 LookupResult lookup; 1032 global->LocalLookup(*name, &lookup); 1033 if (!lookup.IsProperty()) { 1034 return global->IgnoreAttributesAndSetLocalProperty(*name, 1035 *value, 1036 attributes); 1037 } 1038 1039 // Determine if this is a redeclaration of something not 1040 // read-only. In case the result is hidden behind an interceptor we 1041 // need to ask it for the property attributes. 1042 if (!lookup.IsReadOnly()) { 1043 if (lookup.type() != INTERCEPTOR) { 1044 return ThrowRedeclarationError("var", name); 1045 } 1046 1047 PropertyAttributes intercepted = global->GetPropertyAttribute(*name); 1048 1049 // Throw re-declaration error if the intercepted property is present 1050 // but not read-only. 1051 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { 1052 return ThrowRedeclarationError("var", name); 1053 } 1054 1055 // Restore global object from context (in case of GC) and continue 1056 // with setting the value because the property is either absent or 1057 // read-only. We also have to do redo the lookup. 1058 global = Top::context()->global(); 1059 1060 // BUG 1213579: Handle the case where we have to set a read-only 1061 // property through an interceptor and only do it if it's 1062 // uninitialized, e.g. the hole. Nirk... 1063 global->SetProperty(*name, *value, attributes); 1064 return *value; 1065 } 1066 1067 // Set the value, but only we're assigning the initial value to a 1068 // constant. For now, we determine this by checking if the 1069 // current value is the hole. 1070 PropertyType type = lookup.type(); 1071 if (type == FIELD) { 1072 FixedArray* properties = global->properties(); 1073 int index = lookup.GetFieldIndex(); 1074 if (properties->get(index)->IsTheHole()) { 1075 properties->set(index, *value); 1076 } 1077 } else if (type == NORMAL) { 1078 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) { 1079 global->SetNormalizedProperty(&lookup, *value); 1080 } 1081 } else { 1082 // Ignore re-initialization of constants that have already been 1083 // assigned a function value. 1084 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION); 1085 } 1086 1087 // Use the set value as the result of the operation. 1088 return *value; 1089} 1090 1091 1092static Object* Runtime_InitializeConstContextSlot(Arguments args) { 1093 HandleScope scope; 1094 ASSERT(args.length() == 3); 1095 1096 Handle<Object> value(args[0]); 1097 ASSERT(!value->IsTheHole()); 1098 CONVERT_ARG_CHECKED(Context, context, 1); 1099 Handle<String> name(String::cast(args[2])); 1100 1101 // Initializations are always done in the function context. 1102 context = Handle<Context>(context->fcontext()); 1103 1104 int index; 1105 PropertyAttributes attributes; 1106 ContextLookupFlags flags = FOLLOW_CHAINS; 1107 Handle<Object> holder = 1108 context->Lookup(name, flags, &index, &attributes); 1109 1110 // In most situations, the property introduced by the const 1111 // declaration should be present in the context extension object. 1112 // However, because declaration and initialization are separate, the 1113 // property might have been deleted (if it was introduced by eval) 1114 // before we reach the initialization point. 1115 // 1116 // Example: 1117 // 1118 // function f() { eval("delete x; const x;"); } 1119 // 1120 // In that case, the initialization behaves like a normal assignment 1121 // to property 'x'. 1122 if (index >= 0) { 1123 // Property was found in a context. 1124 if (holder->IsContext()) { 1125 // The holder cannot be the function context. If it is, there 1126 // should have been a const redeclaration error when declaring 1127 // the const property. 1128 ASSERT(!holder.is_identical_to(context)); 1129 if ((attributes & READ_ONLY) == 0) { 1130 Handle<Context>::cast(holder)->set(index, *value); 1131 } 1132 } else { 1133 // The holder is an arguments object. 1134 ASSERT((attributes & READ_ONLY) == 0); 1135 Handle<JSObject>::cast(holder)->SetElement(index, *value); 1136 } 1137 return *value; 1138 } 1139 1140 // The property could not be found, we introduce it in the global 1141 // context. 1142 if (attributes == ABSENT) { 1143 Handle<JSObject> global = Handle<JSObject>(Top::context()->global()); 1144 SetProperty(global, name, value, NONE); 1145 return *value; 1146 } 1147 1148 // The property was present in a context extension object. 1149 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); 1150 1151 if (*context_ext == context->extension()) { 1152 // This is the property that was introduced by the const 1153 // declaration. Set it if it hasn't been set before. NOTE: We 1154 // cannot use GetProperty() to get the current value as it 1155 // 'unholes' the value. 1156 LookupResult lookup; 1157 context_ext->LocalLookupRealNamedProperty(*name, &lookup); 1158 ASSERT(lookup.IsProperty()); // the property was declared 1159 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only 1160 1161 PropertyType type = lookup.type(); 1162 if (type == FIELD) { 1163 FixedArray* properties = context_ext->properties(); 1164 int index = lookup.GetFieldIndex(); 1165 if (properties->get(index)->IsTheHole()) { 1166 properties->set(index, *value); 1167 } 1168 } else if (type == NORMAL) { 1169 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) { 1170 context_ext->SetNormalizedProperty(&lookup, *value); 1171 } 1172 } else { 1173 // We should not reach here. Any real, named property should be 1174 // either a field or a dictionary slot. 1175 UNREACHABLE(); 1176 } 1177 } else { 1178 // The property was found in a different context extension object. 1179 // Set it if it is not a read-only property. 1180 if ((attributes & READ_ONLY) == 0) { 1181 Handle<Object> set = SetProperty(context_ext, name, value, attributes); 1182 // Setting a property might throw an exception. Exceptions 1183 // are converted to empty handles in handle operations. We 1184 // need to convert back to exceptions here. 1185 if (set.is_null()) { 1186 ASSERT(Top::has_pending_exception()); 1187 return Failure::Exception(); 1188 } 1189 } 1190 } 1191 1192 return *value; 1193} 1194 1195 1196static Object* Runtime_OptimizeObjectForAddingMultipleProperties( 1197 Arguments args) { 1198 HandleScope scope; 1199 ASSERT(args.length() == 2); 1200 CONVERT_ARG_CHECKED(JSObject, object, 0); 1201 CONVERT_SMI_CHECKED(properties, args[1]); 1202 if (object->HasFastProperties()) { 1203 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); 1204 } 1205 return *object; 1206} 1207 1208 1209static Object* Runtime_RegExpExec(Arguments args) { 1210 HandleScope scope; 1211 ASSERT(args.length() == 4); 1212 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); 1213 CONVERT_ARG_CHECKED(String, subject, 1); 1214 // Due to the way the JS calls are constructed this must be less than the 1215 // length of a string, i.e. it is always a Smi. We check anyway for security. 1216 CONVERT_SMI_CHECKED(index, args[2]); 1217 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3); 1218 RUNTIME_ASSERT(last_match_info->HasFastElements()); 1219 RUNTIME_ASSERT(index >= 0); 1220 RUNTIME_ASSERT(index <= subject->length()); 1221 Counters::regexp_entry_runtime.Increment(); 1222 Handle<Object> result = RegExpImpl::Exec(regexp, 1223 subject, 1224 index, 1225 last_match_info); 1226 if (result.is_null()) return Failure::Exception(); 1227 return *result; 1228} 1229 1230 1231static Object* Runtime_RegExpConstructResult(Arguments args) { 1232 ASSERT(args.length() == 3); 1233 CONVERT_SMI_CHECKED(elements_count, args[0]); 1234 if (elements_count > JSArray::kMaxFastElementsLength) { 1235 return Top::ThrowIllegalOperation(); 1236 } 1237 Object* new_object = Heap::AllocateFixedArrayWithHoles(elements_count); 1238 if (new_object->IsFailure()) return new_object; 1239 FixedArray* elements = FixedArray::cast(new_object); 1240 new_object = Heap::AllocateRaw(JSRegExpResult::kSize, 1241 NEW_SPACE, 1242 OLD_POINTER_SPACE); 1243 if (new_object->IsFailure()) return new_object; 1244 { 1245 AssertNoAllocation no_gc; 1246 HandleScope scope; 1247 reinterpret_cast<HeapObject*>(new_object)-> 1248 set_map(Top::global_context()->regexp_result_map()); 1249 } 1250 JSArray* array = JSArray::cast(new_object); 1251 array->set_properties(Heap::empty_fixed_array()); 1252 array->set_elements(elements); 1253 array->set_length(Smi::FromInt(elements_count)); 1254 // Write in-object properties after the length of the array. 1255 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]); 1256 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]); 1257 return array; 1258} 1259 1260 1261static Object* Runtime_RegExpInitializeObject(Arguments args) { 1262 AssertNoAllocation no_alloc; 1263 ASSERT(args.length() == 5); 1264 CONVERT_CHECKED(JSRegExp, regexp, args[0]); 1265 CONVERT_CHECKED(String, source, args[1]); 1266 1267 Object* global = args[2]; 1268 if (!global->IsTrue()) global = Heap::false_value(); 1269 1270 Object* ignoreCase = args[3]; 1271 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value(); 1272 1273 Object* multiline = args[4]; 1274 if (!multiline->IsTrue()) multiline = Heap::false_value(); 1275 1276 Map* map = regexp->map(); 1277 Object* constructor = map->constructor(); 1278 if (constructor->IsJSFunction() && 1279 JSFunction::cast(constructor)->initial_map() == map) { 1280 // If we still have the original map, set in-object properties directly. 1281 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source); 1282 // TODO(lrn): Consider skipping write barrier on booleans as well. 1283 // Both true and false should be in oldspace at all times. 1284 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global); 1285 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase); 1286 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline); 1287 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, 1288 Smi::FromInt(0), 1289 SKIP_WRITE_BARRIER); 1290 return regexp; 1291 } 1292 1293 // Map has changed, so use generic, but slower, method. 1294 PropertyAttributes final = 1295 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); 1296 PropertyAttributes writable = 1297 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); 1298 regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(), 1299 source, 1300 final); 1301 regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(), 1302 global, 1303 final); 1304 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(), 1305 ignoreCase, 1306 final); 1307 regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(), 1308 multiline, 1309 final); 1310 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(), 1311 Smi::FromInt(0), 1312 writable); 1313 return regexp; 1314} 1315 1316 1317static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) { 1318 HandleScope scope; 1319 ASSERT(args.length() == 1); 1320 CONVERT_ARG_CHECKED(JSArray, prototype, 0); 1321 // This is necessary to enable fast checks for absence of elements 1322 // on Array.prototype and below. 1323 prototype->set_elements(Heap::empty_fixed_array()); 1324 return Smi::FromInt(0); 1325} 1326 1327 1328static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder, 1329 const char* name, 1330 Builtins::Name builtin_name) { 1331 Handle<String> key = Factory::LookupAsciiSymbol(name); 1332 Handle<Code> code(Builtins::builtin(builtin_name)); 1333 Handle<JSFunction> optimized = Factory::NewFunction(key, 1334 JS_OBJECT_TYPE, 1335 JSObject::kHeaderSize, 1336 code, 1337 false); 1338 optimized->shared()->DontAdaptArguments(); 1339 SetProperty(holder, key, optimized, NONE); 1340 return optimized; 1341} 1342 1343 1344static Object* Runtime_SpecialArrayFunctions(Arguments args) { 1345 HandleScope scope; 1346 ASSERT(args.length() == 1); 1347 CONVERT_ARG_CHECKED(JSObject, holder, 0); 1348 1349 InstallBuiltin(holder, "pop", Builtins::ArrayPop); 1350 InstallBuiltin(holder, "push", Builtins::ArrayPush); 1351 InstallBuiltin(holder, "shift", Builtins::ArrayShift); 1352 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift); 1353 InstallBuiltin(holder, "slice", Builtins::ArraySlice); 1354 InstallBuiltin(holder, "splice", Builtins::ArraySplice); 1355 InstallBuiltin(holder, "concat", Builtins::ArrayConcat); 1356 1357 return *holder; 1358} 1359 1360 1361static Object* Runtime_GetGlobalReceiver(Arguments args) { 1362 // Returns a real global receiver, not one of builtins object. 1363 Context* global_context = Top::context()->global()->global_context(); 1364 return global_context->global()->global_receiver(); 1365} 1366 1367 1368static Object* Runtime_MaterializeRegExpLiteral(Arguments args) { 1369 HandleScope scope; 1370 ASSERT(args.length() == 4); 1371 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 1372 int index = Smi::cast(args[1])->value(); 1373 Handle<String> pattern = args.at<String>(2); 1374 Handle<String> flags = args.at<String>(3); 1375 1376 // Get the RegExp function from the context in the literals array. 1377 // This is the RegExp function from the context in which the 1378 // function was created. We do not use the RegExp function from the 1379 // current global context because this might be the RegExp function 1380 // from another context which we should not have access to. 1381 Handle<JSFunction> constructor = 1382 Handle<JSFunction>( 1383 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function()); 1384 // Compute the regular expression literal. 1385 bool has_pending_exception; 1386 Handle<Object> regexp = 1387 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags, 1388 &has_pending_exception); 1389 if (has_pending_exception) { 1390 ASSERT(Top::has_pending_exception()); 1391 return Failure::Exception(); 1392 } 1393 literals->set(index, *regexp); 1394 return *regexp; 1395} 1396 1397 1398static Object* Runtime_FunctionGetName(Arguments args) { 1399 NoHandleAllocation ha; 1400 ASSERT(args.length() == 1); 1401 1402 CONVERT_CHECKED(JSFunction, f, args[0]); 1403 return f->shared()->name(); 1404} 1405 1406 1407static Object* Runtime_FunctionSetName(Arguments args) { 1408 NoHandleAllocation ha; 1409 ASSERT(args.length() == 2); 1410 1411 CONVERT_CHECKED(JSFunction, f, args[0]); 1412 CONVERT_CHECKED(String, name, args[1]); 1413 f->shared()->set_name(name); 1414 return Heap::undefined_value(); 1415} 1416 1417 1418static Object* Runtime_FunctionRemovePrototype(Arguments args) { 1419 NoHandleAllocation ha; 1420 ASSERT(args.length() == 1); 1421 1422 CONVERT_CHECKED(JSFunction, f, args[0]); 1423 Object* obj = f->RemovePrototype(); 1424 if (obj->IsFailure()) return obj; 1425 1426 return Heap::undefined_value(); 1427} 1428 1429 1430static Object* Runtime_FunctionGetScript(Arguments args) { 1431 HandleScope scope; 1432 ASSERT(args.length() == 1); 1433 1434 CONVERT_CHECKED(JSFunction, fun, args[0]); 1435 Handle<Object> script = Handle<Object>(fun->shared()->script()); 1436 if (!script->IsScript()) return Heap::undefined_value(); 1437 1438 return *GetScriptWrapper(Handle<Script>::cast(script)); 1439} 1440 1441 1442static Object* Runtime_FunctionGetSourceCode(Arguments args) { 1443 NoHandleAllocation ha; 1444 ASSERT(args.length() == 1); 1445 1446 CONVERT_CHECKED(JSFunction, f, args[0]); 1447 return f->shared()->GetSourceCode(); 1448} 1449 1450 1451static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) { 1452 NoHandleAllocation ha; 1453 ASSERT(args.length() == 1); 1454 1455 CONVERT_CHECKED(JSFunction, fun, args[0]); 1456 int pos = fun->shared()->start_position(); 1457 return Smi::FromInt(pos); 1458} 1459 1460 1461static Object* Runtime_FunctionGetPositionForOffset(Arguments args) { 1462 ASSERT(args.length() == 2); 1463 1464 CONVERT_CHECKED(JSFunction, fun, args[0]); 1465 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); 1466 1467 Code* code = fun->code(); 1468 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); 1469 1470 Address pc = code->address() + offset; 1471 return Smi::FromInt(fun->code()->SourcePosition(pc)); 1472} 1473 1474 1475 1476static Object* Runtime_FunctionSetInstanceClassName(Arguments args) { 1477 NoHandleAllocation ha; 1478 ASSERT(args.length() == 2); 1479 1480 CONVERT_CHECKED(JSFunction, fun, args[0]); 1481 CONVERT_CHECKED(String, name, args[1]); 1482 fun->SetInstanceClassName(name); 1483 return Heap::undefined_value(); 1484} 1485 1486 1487static Object* Runtime_FunctionSetLength(Arguments args) { 1488 NoHandleAllocation ha; 1489 ASSERT(args.length() == 2); 1490 1491 CONVERT_CHECKED(JSFunction, fun, args[0]); 1492 CONVERT_CHECKED(Smi, length, args[1]); 1493 fun->shared()->set_length(length->value()); 1494 return length; 1495} 1496 1497 1498static Object* Runtime_FunctionSetPrototype(Arguments args) { 1499 NoHandleAllocation ha; 1500 ASSERT(args.length() == 2); 1501 1502 CONVERT_CHECKED(JSFunction, fun, args[0]); 1503 ASSERT(fun->should_have_prototype()); 1504 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL); 1505 if (obj->IsFailure()) return obj; 1506 return args[0]; // return TOS 1507} 1508 1509 1510static Object* Runtime_FunctionIsAPIFunction(Arguments args) { 1511 NoHandleAllocation ha; 1512 ASSERT(args.length() == 1); 1513 1514 CONVERT_CHECKED(JSFunction, f, args[0]); 1515 return f->shared()->IsApiFunction() ? Heap::true_value() 1516 : Heap::false_value(); 1517} 1518 1519static Object* Runtime_FunctionIsBuiltin(Arguments args) { 1520 NoHandleAllocation ha; 1521 ASSERT(args.length() == 1); 1522 1523 CONVERT_CHECKED(JSFunction, f, args[0]); 1524 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value(); 1525} 1526 1527 1528static Object* Runtime_SetCode(Arguments args) { 1529 HandleScope scope; 1530 ASSERT(args.length() == 2); 1531 1532 CONVERT_ARG_CHECKED(JSFunction, target, 0); 1533 Handle<Object> code = args.at<Object>(1); 1534 1535 Handle<Context> context(target->context()); 1536 1537 if (!code->IsNull()) { 1538 RUNTIME_ASSERT(code->IsJSFunction()); 1539 Handle<JSFunction> fun = Handle<JSFunction>::cast(code); 1540 Handle<SharedFunctionInfo> shared(fun->shared()); 1541 SetExpectedNofProperties(target, shared->expected_nof_properties()); 1542 1543 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) { 1544 return Failure::Exception(); 1545 } 1546 // Set the code, formal parameter count, and the length of the target 1547 // function. 1548 target->set_code(fun->code()); 1549 target->shared()->set_length(shared->length()); 1550 target->shared()->set_formal_parameter_count( 1551 shared->formal_parameter_count()); 1552 // Set the source code of the target function to undefined. 1553 // SetCode is only used for built-in constructors like String, 1554 // Array, and Object, and some web code 1555 // doesn't like seeing source code for constructors. 1556 target->shared()->set_script(Heap::undefined_value()); 1557 // Clear the optimization hints related to the compiled code as these are no 1558 // longer valid when the code is overwritten. 1559 target->shared()->ClearThisPropertyAssignmentsInfo(); 1560 context = Handle<Context>(fun->context()); 1561 1562 // Make sure we get a fresh copy of the literal vector to avoid 1563 // cross context contamination. 1564 int number_of_literals = fun->NumberOfLiterals(); 1565 Handle<FixedArray> literals = 1566 Factory::NewFixedArray(number_of_literals, TENURED); 1567 if (number_of_literals > 0) { 1568 // Insert the object, regexp and array functions in the literals 1569 // array prefix. These are the functions that will be used when 1570 // creating object, regexp and array literals. 1571 literals->set(JSFunction::kLiteralGlobalContextIndex, 1572 context->global_context()); 1573 } 1574 // It's okay to skip the write barrier here because the literals 1575 // are guaranteed to be in old space. 1576 target->set_literals(*literals, SKIP_WRITE_BARRIER); 1577 } 1578 1579 target->set_context(*context); 1580 return *target; 1581} 1582 1583 1584static Object* CharCodeAt(String* subject, Object* index) { 1585 uint32_t i = 0; 1586 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); 1587 // Flatten the string. If someone wants to get a char at an index 1588 // in a cons string, it is likely that more indices will be 1589 // accessed. 1590 Object* flat = subject->TryFlatten(); 1591 if (flat->IsFailure()) return flat; 1592 subject = String::cast(flat); 1593 if (i >= static_cast<uint32_t>(subject->length())) { 1594 return Heap::nan_value(); 1595 } 1596 return Smi::FromInt(subject->Get(i)); 1597} 1598 1599 1600static Object* CharFromCode(Object* char_code) { 1601 uint32_t code; 1602 if (Array::IndexFromObject(char_code, &code)) { 1603 if (code <= 0xffff) { 1604 return Heap::LookupSingleCharacterStringFromCode(code); 1605 } 1606 } 1607 return Heap::empty_string(); 1608} 1609 1610 1611static Object* Runtime_StringCharCodeAt(Arguments args) { 1612 NoHandleAllocation ha; 1613 ASSERT(args.length() == 2); 1614 1615 CONVERT_CHECKED(String, subject, args[0]); 1616 Object* index = args[1]; 1617 return CharCodeAt(subject, index); 1618} 1619 1620 1621static Object* Runtime_StringCharAt(Arguments args) { 1622 NoHandleAllocation ha; 1623 ASSERT(args.length() == 2); 1624 1625 CONVERT_CHECKED(String, subject, args[0]); 1626 Object* index = args[1]; 1627 Object* code = CharCodeAt(subject, index); 1628 if (code == Heap::nan_value()) { 1629 return Heap::undefined_value(); 1630 } 1631 return CharFromCode(code); 1632} 1633 1634 1635static Object* Runtime_CharFromCode(Arguments args) { 1636 NoHandleAllocation ha; 1637 ASSERT(args.length() == 1); 1638 return CharFromCode(args[0]); 1639} 1640 1641 1642class FixedArrayBuilder { 1643 public: 1644 explicit FixedArrayBuilder(int initial_capacity) 1645 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)), 1646 length_(0) { 1647 // Require a non-zero initial size. Ensures that doubling the size to 1648 // extend the array will work. 1649 ASSERT(initial_capacity > 0); 1650 } 1651 1652 explicit FixedArrayBuilder(Handle<FixedArray> backing_store) 1653 : array_(backing_store), 1654 length_(0) { 1655 // Require a non-zero initial size. Ensures that doubling the size to 1656 // extend the array will work. 1657 ASSERT(backing_store->length() > 0); 1658 } 1659 1660 bool HasCapacity(int elements) { 1661 int length = array_->length(); 1662 int required_length = length_ + elements; 1663 return (length >= required_length); 1664 } 1665 1666 void EnsureCapacity(int elements) { 1667 int length = array_->length(); 1668 int required_length = length_ + elements; 1669 if (length < required_length) { 1670 int new_length = length; 1671 do { 1672 new_length *= 2; 1673 } while (new_length < required_length); 1674 Handle<FixedArray> extended_array = 1675 Factory::NewFixedArrayWithHoles(new_length); 1676 array_->CopyTo(0, *extended_array, 0, length_); 1677 array_ = extended_array; 1678 } 1679 } 1680 1681 void Add(Object* value) { 1682 ASSERT(length_ < capacity()); 1683 array_->set(length_, value); 1684 length_++; 1685 } 1686 1687 void Add(Smi* value) { 1688 ASSERT(length_ < capacity()); 1689 array_->set(length_, value); 1690 length_++; 1691 } 1692 1693 Handle<FixedArray> array() { 1694 return array_; 1695 } 1696 1697 int length() { 1698 return length_; 1699 } 1700 1701 int capacity() { 1702 return array_->length(); 1703 } 1704 1705 Handle<JSArray> ToJSArray() { 1706 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_); 1707 result_array->set_length(Smi::FromInt(length_)); 1708 return result_array; 1709 } 1710 1711 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { 1712 target_array->set_elements(*array_); 1713 target_array->set_length(Smi::FromInt(length_)); 1714 return target_array; 1715 } 1716 1717 private: 1718 Handle<FixedArray> array_; 1719 int length_; 1720}; 1721 1722 1723// Forward declarations. 1724const int kStringBuilderConcatHelperLengthBits = 11; 1725const int kStringBuilderConcatHelperPositionBits = 19; 1726 1727template <typename schar> 1728static inline void StringBuilderConcatHelper(String*, 1729 schar*, 1730 FixedArray*, 1731 int); 1732 1733typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> 1734 StringBuilderSubstringLength; 1735typedef BitField<int, 1736 kStringBuilderConcatHelperLengthBits, 1737 kStringBuilderConcatHelperPositionBits> 1738 StringBuilderSubstringPosition; 1739 1740 1741class ReplacementStringBuilder { 1742 public: 1743 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) 1744 : array_builder_(estimated_part_count), 1745 subject_(subject), 1746 character_count_(0), 1747 is_ascii_(subject->IsAsciiRepresentation()) { 1748 // Require a non-zero initial size. Ensures that doubling the size to 1749 // extend the array will work. 1750 ASSERT(estimated_part_count > 0); 1751 } 1752 1753 static inline void AddSubjectSlice(FixedArrayBuilder* builder, 1754 int from, 1755 int to) { 1756 ASSERT(from >= 0); 1757 int length = to - from; 1758 ASSERT(length > 0); 1759 if (StringBuilderSubstringLength::is_valid(length) && 1760 StringBuilderSubstringPosition::is_valid(from)) { 1761 int encoded_slice = StringBuilderSubstringLength::encode(length) | 1762 StringBuilderSubstringPosition::encode(from); 1763 builder->Add(Smi::FromInt(encoded_slice)); 1764 } else { 1765 // Otherwise encode as two smis. 1766 builder->Add(Smi::FromInt(-length)); 1767 builder->Add(Smi::FromInt(from)); 1768 } 1769 } 1770 1771 1772 void EnsureCapacity(int elements) { 1773 array_builder_.EnsureCapacity(elements); 1774 } 1775 1776 1777 void AddSubjectSlice(int from, int to) { 1778 AddSubjectSlice(&array_builder_, from, to); 1779 IncrementCharacterCount(to - from); 1780 } 1781 1782 1783 void AddString(Handle<String> string) { 1784 int length = string->length(); 1785 ASSERT(length > 0); 1786 AddElement(*string); 1787 if (!string->IsAsciiRepresentation()) { 1788 is_ascii_ = false; 1789 } 1790 IncrementCharacterCount(length); 1791 } 1792 1793 1794 Handle<String> ToString() { 1795 if (array_builder_.length() == 0) { 1796 return Factory::empty_string(); 1797 } 1798 1799 Handle<String> joined_string; 1800 if (is_ascii_) { 1801 joined_string = NewRawAsciiString(character_count_); 1802 AssertNoAllocation no_alloc; 1803 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); 1804 char* char_buffer = seq->GetChars(); 1805 StringBuilderConcatHelper(*subject_, 1806 char_buffer, 1807 *array_builder_.array(), 1808 array_builder_.length()); 1809 } else { 1810 // Non-ASCII. 1811 joined_string = NewRawTwoByteString(character_count_); 1812 AssertNoAllocation no_alloc; 1813 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); 1814 uc16* char_buffer = seq->GetChars(); 1815 StringBuilderConcatHelper(*subject_, 1816 char_buffer, 1817 *array_builder_.array(), 1818 array_builder_.length()); 1819 } 1820 return joined_string; 1821 } 1822 1823 1824 void IncrementCharacterCount(int by) { 1825 if (character_count_ > String::kMaxLength - by) { 1826 V8::FatalProcessOutOfMemory("String.replace result too large."); 1827 } 1828 character_count_ += by; 1829 } 1830 1831 Handle<JSArray> GetParts() { 1832 Handle<JSArray> result = 1833 Factory::NewJSArrayWithElements(array_builder_.array()); 1834 result->set_length(Smi::FromInt(array_builder_.length())); 1835 return result; 1836 } 1837 1838 private: 1839 Handle<String> NewRawAsciiString(int size) { 1840 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String); 1841 } 1842 1843 1844 Handle<String> NewRawTwoByteString(int size) { 1845 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String); 1846 } 1847 1848 1849 void AddElement(Object* element) { 1850 ASSERT(element->IsSmi() || element->IsString()); 1851 ASSERT(array_builder_.capacity() > array_builder_.length()); 1852 array_builder_.Add(element); 1853 } 1854 1855 FixedArrayBuilder array_builder_; 1856 Handle<String> subject_; 1857 int character_count_; 1858 bool is_ascii_; 1859}; 1860 1861 1862class CompiledReplacement { 1863 public: 1864 CompiledReplacement() 1865 : parts_(1), replacement_substrings_(0) {} 1866 1867 void Compile(Handle<String> replacement, 1868 int capture_count, 1869 int subject_length); 1870 1871 void Apply(ReplacementStringBuilder* builder, 1872 int match_from, 1873 int match_to, 1874 Handle<JSArray> last_match_info); 1875 1876 // Number of distinct parts of the replacement pattern. 1877 int parts() { 1878 return parts_.length(); 1879 } 1880 private: 1881 enum PartType { 1882 SUBJECT_PREFIX = 1, 1883 SUBJECT_SUFFIX, 1884 SUBJECT_CAPTURE, 1885 REPLACEMENT_SUBSTRING, 1886 REPLACEMENT_STRING, 1887 1888 NUMBER_OF_PART_TYPES 1889 }; 1890 1891 struct ReplacementPart { 1892 static inline ReplacementPart SubjectMatch() { 1893 return ReplacementPart(SUBJECT_CAPTURE, 0); 1894 } 1895 static inline ReplacementPart SubjectCapture(int capture_index) { 1896 return ReplacementPart(SUBJECT_CAPTURE, capture_index); 1897 } 1898 static inline ReplacementPart SubjectPrefix() { 1899 return ReplacementPart(SUBJECT_PREFIX, 0); 1900 } 1901 static inline ReplacementPart SubjectSuffix(int subject_length) { 1902 return ReplacementPart(SUBJECT_SUFFIX, subject_length); 1903 } 1904 static inline ReplacementPart ReplacementString() { 1905 return ReplacementPart(REPLACEMENT_STRING, 0); 1906 } 1907 static inline ReplacementPart ReplacementSubString(int from, int to) { 1908 ASSERT(from >= 0); 1909 ASSERT(to > from); 1910 return ReplacementPart(-from, to); 1911 } 1912 1913 // If tag <= 0 then it is the negation of a start index of a substring of 1914 // the replacement pattern, otherwise it's a value from PartType. 1915 ReplacementPart(int tag, int data) 1916 : tag(tag), data(data) { 1917 // Must be non-positive or a PartType value. 1918 ASSERT(tag < NUMBER_OF_PART_TYPES); 1919 } 1920 // Either a value of PartType or a non-positive number that is 1921 // the negation of an index into the replacement string. 1922 int tag; 1923 // The data value's interpretation depends on the value of tag: 1924 // tag == SUBJECT_PREFIX || 1925 // tag == SUBJECT_SUFFIX: data is unused. 1926 // tag == SUBJECT_CAPTURE: data is the number of the capture. 1927 // tag == REPLACEMENT_SUBSTRING || 1928 // tag == REPLACEMENT_STRING: data is index into array of substrings 1929 // of the replacement string. 1930 // tag <= 0: Temporary representation of the substring of the replacement 1931 // string ranging over -tag .. data. 1932 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the 1933 // substring objects. 1934 int data; 1935 }; 1936 1937 template<typename Char> 1938 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts, 1939 Vector<Char> characters, 1940 int capture_count, 1941 int subject_length) { 1942 int length = characters.length(); 1943 int last = 0; 1944 for (int i = 0; i < length; i++) { 1945 Char c = characters[i]; 1946 if (c == '$') { 1947 int next_index = i + 1; 1948 if (next_index == length) { // No next character! 1949 break; 1950 } 1951 Char c2 = characters[next_index]; 1952 switch (c2) { 1953 case '$': 1954 if (i > last) { 1955 // There is a substring before. Include the first "$". 1956 parts->Add(ReplacementPart::ReplacementSubString(last, next_index)); 1957 last = next_index + 1; // Continue after the second "$". 1958 } else { 1959 // Let the next substring start with the second "$". 1960 last = next_index; 1961 } 1962 i = next_index; 1963 break; 1964 case '`': 1965 if (i > last) { 1966 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 1967 } 1968 parts->Add(ReplacementPart::SubjectPrefix()); 1969 i = next_index; 1970 last = i + 1; 1971 break; 1972 case '\'': 1973 if (i > last) { 1974 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 1975 } 1976 parts->Add(ReplacementPart::SubjectSuffix(subject_length)); 1977 i = next_index; 1978 last = i + 1; 1979 break; 1980 case '&': 1981 if (i > last) { 1982 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 1983 } 1984 parts->Add(ReplacementPart::SubjectMatch()); 1985 i = next_index; 1986 last = i + 1; 1987 break; 1988 case '0': 1989 case '1': 1990 case '2': 1991 case '3': 1992 case '4': 1993 case '5': 1994 case '6': 1995 case '7': 1996 case '8': 1997 case '9': { 1998 int capture_ref = c2 - '0'; 1999 if (capture_ref > capture_count) { 2000 i = next_index; 2001 continue; 2002 } 2003 int second_digit_index = next_index + 1; 2004 if (second_digit_index < length) { 2005 // Peek ahead to see if we have two digits. 2006 Char c3 = characters[second_digit_index]; 2007 if ('0' <= c3 && c3 <= '9') { // Double digits. 2008 int double_digit_ref = capture_ref * 10 + c3 - '0'; 2009 if (double_digit_ref <= capture_count) { 2010 next_index = second_digit_index; 2011 capture_ref = double_digit_ref; 2012 } 2013 } 2014 } 2015 if (capture_ref > 0) { 2016 if (i > last) { 2017 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 2018 } 2019 ASSERT(capture_ref <= capture_count); 2020 parts->Add(ReplacementPart::SubjectCapture(capture_ref)); 2021 last = next_index + 1; 2022 } 2023 i = next_index; 2024 break; 2025 } 2026 default: 2027 i = next_index; 2028 break; 2029 } 2030 } 2031 } 2032 if (length > last) { 2033 if (last == 0) { 2034 parts->Add(ReplacementPart::ReplacementString()); 2035 } else { 2036 parts->Add(ReplacementPart::ReplacementSubString(last, length)); 2037 } 2038 } 2039 } 2040 2041 ZoneList<ReplacementPart> parts_; 2042 ZoneList<Handle<String> > replacement_substrings_; 2043}; 2044 2045 2046void CompiledReplacement::Compile(Handle<String> replacement, 2047 int capture_count, 2048 int subject_length) { 2049 ASSERT(replacement->IsFlat()); 2050 if (replacement->IsAsciiRepresentation()) { 2051 AssertNoAllocation no_alloc; 2052 ParseReplacementPattern(&parts_, 2053 replacement->ToAsciiVector(), 2054 capture_count, 2055 subject_length); 2056 } else { 2057 ASSERT(replacement->IsTwoByteRepresentation()); 2058 AssertNoAllocation no_alloc; 2059 2060 ParseReplacementPattern(&parts_, 2061 replacement->ToUC16Vector(), 2062 capture_count, 2063 subject_length); 2064 } 2065 // Find substrings of replacement string and create them as String objects. 2066 int substring_index = 0; 2067 for (int i = 0, n = parts_.length(); i < n; i++) { 2068 int tag = parts_[i].tag; 2069 if (tag <= 0) { // A replacement string slice. 2070 int from = -tag; 2071 int to = parts_[i].data; 2072 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to)); 2073 parts_[i].tag = REPLACEMENT_SUBSTRING; 2074 parts_[i].data = substring_index; 2075 substring_index++; 2076 } else if (tag == REPLACEMENT_STRING) { 2077 replacement_substrings_.Add(replacement); 2078 parts_[i].data = substring_index; 2079 substring_index++; 2080 } 2081 } 2082} 2083 2084 2085void CompiledReplacement::Apply(ReplacementStringBuilder* builder, 2086 int match_from, 2087 int match_to, 2088 Handle<JSArray> last_match_info) { 2089 for (int i = 0, n = parts_.length(); i < n; i++) { 2090 ReplacementPart part = parts_[i]; 2091 switch (part.tag) { 2092 case SUBJECT_PREFIX: 2093 if (match_from > 0) builder->AddSubjectSlice(0, match_from); 2094 break; 2095 case SUBJECT_SUFFIX: { 2096 int subject_length = part.data; 2097 if (match_to < subject_length) { 2098 builder->AddSubjectSlice(match_to, subject_length); 2099 } 2100 break; 2101 } 2102 case SUBJECT_CAPTURE: { 2103 int capture = part.data; 2104 FixedArray* match_info = FixedArray::cast(last_match_info->elements()); 2105 int from = RegExpImpl::GetCapture(match_info, capture * 2); 2106 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1); 2107 if (from >= 0 && to > from) { 2108 builder->AddSubjectSlice(from, to); 2109 } 2110 break; 2111 } 2112 case REPLACEMENT_SUBSTRING: 2113 case REPLACEMENT_STRING: 2114 builder->AddString(replacement_substrings_[part.data]); 2115 break; 2116 default: 2117 UNREACHABLE(); 2118 } 2119 } 2120} 2121 2122 2123 2124static Object* StringReplaceRegExpWithString(String* subject, 2125 JSRegExp* regexp, 2126 String* replacement, 2127 JSArray* last_match_info) { 2128 ASSERT(subject->IsFlat()); 2129 ASSERT(replacement->IsFlat()); 2130 2131 HandleScope handles; 2132 2133 int length = subject->length(); 2134 Handle<String> subject_handle(subject); 2135 Handle<JSRegExp> regexp_handle(regexp); 2136 Handle<String> replacement_handle(replacement); 2137 Handle<JSArray> last_match_info_handle(last_match_info); 2138 Handle<Object> match = RegExpImpl::Exec(regexp_handle, 2139 subject_handle, 2140 0, 2141 last_match_info_handle); 2142 if (match.is_null()) { 2143 return Failure::Exception(); 2144 } 2145 if (match->IsNull()) { 2146 return *subject_handle; 2147 } 2148 2149 int capture_count = regexp_handle->CaptureCount(); 2150 2151 // CompiledReplacement uses zone allocation. 2152 CompilationZoneScope zone(DELETE_ON_EXIT); 2153 CompiledReplacement compiled_replacement; 2154 compiled_replacement.Compile(replacement_handle, 2155 capture_count, 2156 length); 2157 2158 bool is_global = regexp_handle->GetFlags().is_global(); 2159 2160 // Guessing the number of parts that the final result string is built 2161 // from. Global regexps can match any number of times, so we guess 2162 // conservatively. 2163 int expected_parts = 2164 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1; 2165 ReplacementStringBuilder builder(subject_handle, expected_parts); 2166 2167 // Index of end of last match. 2168 int prev = 0; 2169 2170 // Number of parts added by compiled replacement plus preceeding 2171 // string and possibly suffix after last match. It is possible for 2172 // all components to use two elements when encoded as two smis. 2173 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); 2174 bool matched = true; 2175 do { 2176 ASSERT(last_match_info_handle->HasFastElements()); 2177 // Increase the capacity of the builder before entering local handle-scope, 2178 // so its internal buffer can safely allocate a new handle if it grows. 2179 builder.EnsureCapacity(parts_added_per_loop); 2180 2181 HandleScope loop_scope; 2182 int start, end; 2183 { 2184 AssertNoAllocation match_info_array_is_not_in_a_handle; 2185 FixedArray* match_info_array = 2186 FixedArray::cast(last_match_info_handle->elements()); 2187 2188 ASSERT_EQ(capture_count * 2 + 2, 2189 RegExpImpl::GetLastCaptureCount(match_info_array)); 2190 start = RegExpImpl::GetCapture(match_info_array, 0); 2191 end = RegExpImpl::GetCapture(match_info_array, 1); 2192 } 2193 2194 if (prev < start) { 2195 builder.AddSubjectSlice(prev, start); 2196 } 2197 compiled_replacement.Apply(&builder, 2198 start, 2199 end, 2200 last_match_info_handle); 2201 prev = end; 2202 2203 // Only continue checking for global regexps. 2204 if (!is_global) break; 2205 2206 // Continue from where the match ended, unless it was an empty match. 2207 int next = end; 2208 if (start == end) { 2209 next = end + 1; 2210 if (next > length) break; 2211 } 2212 2213 match = RegExpImpl::Exec(regexp_handle, 2214 subject_handle, 2215 next, 2216 last_match_info_handle); 2217 if (match.is_null()) { 2218 return Failure::Exception(); 2219 } 2220 matched = !match->IsNull(); 2221 } while (matched); 2222 2223 if (prev < length) { 2224 builder.AddSubjectSlice(prev, length); 2225 } 2226 2227 return *(builder.ToString()); 2228} 2229 2230 2231static Object* Runtime_StringReplaceRegExpWithString(Arguments args) { 2232 ASSERT(args.length() == 4); 2233 2234 CONVERT_CHECKED(String, subject, args[0]); 2235 if (!subject->IsFlat()) { 2236 Object* flat_subject = subject->TryFlatten(); 2237 if (flat_subject->IsFailure()) { 2238 return flat_subject; 2239 } 2240 subject = String::cast(flat_subject); 2241 } 2242 2243 CONVERT_CHECKED(String, replacement, args[2]); 2244 if (!replacement->IsFlat()) { 2245 Object* flat_replacement = replacement->TryFlatten(); 2246 if (flat_replacement->IsFailure()) { 2247 return flat_replacement; 2248 } 2249 replacement = String::cast(flat_replacement); 2250 } 2251 2252 CONVERT_CHECKED(JSRegExp, regexp, args[1]); 2253 CONVERT_CHECKED(JSArray, last_match_info, args[3]); 2254 2255 ASSERT(last_match_info->HasFastElements()); 2256 2257 return StringReplaceRegExpWithString(subject, 2258 regexp, 2259 replacement, 2260 last_match_info); 2261} 2262 2263 2264// Cap on the maximal shift in the Boyer-Moore implementation. By setting a 2265// limit, we can fix the size of tables. 2266static const int kBMMaxShift = 0xff; 2267// Reduce alphabet to this size. 2268static const int kBMAlphabetSize = 0x100; 2269// For patterns below this length, the skip length of Boyer-Moore is too short 2270// to compensate for the algorithmic overhead compared to simple brute force. 2271static const int kBMMinPatternLength = 5; 2272 2273// Holds the two buffers used by Boyer-Moore string search's Good Suffix 2274// shift. Only allows the last kBMMaxShift characters of the needle 2275// to be indexed. 2276class BMGoodSuffixBuffers { 2277 public: 2278 BMGoodSuffixBuffers() {} 2279 inline void init(int needle_length) { 2280 ASSERT(needle_length > 1); 2281 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift; 2282 int len = needle_length - start; 2283 biased_suffixes_ = suffixes_ - start; 2284 biased_good_suffix_shift_ = good_suffix_shift_ - start; 2285 for (int i = 0; i <= len; i++) { 2286 good_suffix_shift_[i] = len; 2287 } 2288 } 2289 inline int& suffix(int index) { 2290 ASSERT(biased_suffixes_ + index >= suffixes_); 2291 return biased_suffixes_[index]; 2292 } 2293 inline int& shift(int index) { 2294 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_); 2295 return biased_good_suffix_shift_[index]; 2296 } 2297 private: 2298 int suffixes_[kBMMaxShift + 1]; 2299 int good_suffix_shift_[kBMMaxShift + 1]; 2300 int* biased_suffixes_; 2301 int* biased_good_suffix_shift_; 2302 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers); 2303}; 2304 2305// buffers reused by BoyerMoore 2306static int bad_char_occurrence[kBMAlphabetSize]; 2307static BMGoodSuffixBuffers bmgs_buffers; 2308 2309// State of the string match tables. 2310// SIMPLE: No usable content in the buffers. 2311// BOYER_MOORE_HORSPOOL: The bad_char_occurences table has been populated. 2312// BOYER_MOORE: The bmgs_buffers tables have also been populated. 2313// Whenever starting with a new needle, one should call InitializeStringSearch 2314// to determine which search strategy to use, and in the case of a long-needle 2315// strategy, the call also initializes the algorithm to SIMPLE. 2316enum StringSearchAlgorithm { SIMPLE_SEARCH, BOYER_MOORE_HORSPOOL, BOYER_MOORE }; 2317static StringSearchAlgorithm algorithm; 2318 2319 2320// Compute the bad-char table for Boyer-Moore in the static buffer. 2321template <typename pchar> 2322static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern) { 2323 // Only preprocess at most kBMMaxShift last characters of pattern. 2324 int start = pattern.length() < kBMMaxShift ? 0 2325 : pattern.length() - kBMMaxShift; 2326 // Run forwards to populate bad_char_table, so that *last* instance 2327 // of character equivalence class is the one registered. 2328 // Notice: Doesn't include the last character. 2329 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1 2330 : kBMAlphabetSize; 2331 if (start == 0) { // All patterns less than kBMMaxShift in length. 2332 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence)); 2333 } else { 2334 for (int i = 0; i < table_size; i++) { 2335 bad_char_occurrence[i] = start - 1; 2336 } 2337 } 2338 for (int i = start; i < pattern.length() - 1; i++) { 2339 pchar c = pattern[i]; 2340 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize; 2341 bad_char_occurrence[bucket] = i; 2342 } 2343} 2344 2345 2346template <typename pchar> 2347static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern) { 2348 int m = pattern.length(); 2349 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; 2350 int len = m - start; 2351 // Compute Good Suffix tables. 2352 bmgs_buffers.init(m); 2353 2354 bmgs_buffers.shift(m-1) = 1; 2355 bmgs_buffers.suffix(m) = m + 1; 2356 pchar last_char = pattern[m - 1]; 2357 int suffix = m + 1; 2358 for (int i = m; i > start;) { 2359 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) { 2360 if (bmgs_buffers.shift(suffix) == len) { 2361 bmgs_buffers.shift(suffix) = suffix - i; 2362 } 2363 suffix = bmgs_buffers.suffix(suffix); 2364 } 2365 i--; 2366 suffix--; 2367 bmgs_buffers.suffix(i) = suffix; 2368 if (suffix == m) { 2369 // No suffix to extend, so we check against last_char only. 2370 while (i > start && pattern[i - 1] != last_char) { 2371 if (bmgs_buffers.shift(m) == len) { 2372 bmgs_buffers.shift(m) = m - i; 2373 } 2374 i--; 2375 bmgs_buffers.suffix(i) = m; 2376 } 2377 if (i > start) { 2378 i--; 2379 suffix--; 2380 bmgs_buffers.suffix(i) = suffix; 2381 } 2382 } 2383 } 2384 if (suffix < m) { 2385 for (int i = start; i <= m; i++) { 2386 if (bmgs_buffers.shift(i) == len) { 2387 bmgs_buffers.shift(i) = suffix - start; 2388 } 2389 if (i == suffix) { 2390 suffix = bmgs_buffers.suffix(suffix); 2391 } 2392 } 2393 } 2394} 2395 2396 2397template <typename schar, typename pchar> 2398static inline int CharOccurrence(int char_code) { 2399 if (sizeof(schar) == 1) { 2400 return bad_char_occurrence[char_code]; 2401 } 2402 if (sizeof(pchar) == 1) { 2403 if (char_code > String::kMaxAsciiCharCode) { 2404 return -1; 2405 } 2406 return bad_char_occurrence[char_code]; 2407 } 2408 return bad_char_occurrence[char_code % kBMAlphabetSize]; 2409} 2410 2411 2412// Restricted simplified Boyer-Moore string matching. 2413// Uses only the bad-shift table of Boyer-Moore and only uses it 2414// for the character compared to the last character of the needle. 2415template <typename schar, typename pchar> 2416static int BoyerMooreHorspool(Vector<const schar> subject, 2417 Vector<const pchar> pattern, 2418 int start_index, 2419 bool* complete) { 2420 ASSERT(algorithm <= BOYER_MOORE_HORSPOOL); 2421 int n = subject.length(); 2422 int m = pattern.length(); 2423 2424 int badness = -m; 2425 2426 // How bad we are doing without a good-suffix table. 2427 int idx; // No matches found prior to this index. 2428 pchar last_char = pattern[m - 1]; 2429 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char); 2430 // Perform search 2431 for (idx = start_index; idx <= n - m;) { 2432 int j = m - 1; 2433 int c; 2434 while (last_char != (c = subject[idx + j])) { 2435 int bc_occ = CharOccurrence<schar, pchar>(c); 2436 int shift = j - bc_occ; 2437 idx += shift; 2438 badness += 1 - shift; // at most zero, so badness cannot increase. 2439 if (idx > n - m) { 2440 *complete = true; 2441 return -1; 2442 } 2443 } 2444 j--; 2445 while (j >= 0 && pattern[j] == (subject[idx + j])) j--; 2446 if (j < 0) { 2447 *complete = true; 2448 return idx; 2449 } else { 2450 idx += last_char_shift; 2451 // Badness increases by the number of characters we have 2452 // checked, and decreases by the number of characters we 2453 // can skip by shifting. It's a measure of how we are doing 2454 // compared to reading each character exactly once. 2455 badness += (m - j) - last_char_shift; 2456 if (badness > 0) { 2457 *complete = false; 2458 return idx; 2459 } 2460 } 2461 } 2462 *complete = true; 2463 return -1; 2464} 2465 2466 2467template <typename schar, typename pchar> 2468static int BoyerMooreIndexOf(Vector<const schar> subject, 2469 Vector<const pchar> pattern, 2470 int idx) { 2471 ASSERT(algorithm <= BOYER_MOORE); 2472 int n = subject.length(); 2473 int m = pattern.length(); 2474 // Only preprocess at most kBMMaxShift last characters of pattern. 2475 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; 2476 2477 pchar last_char = pattern[m - 1]; 2478 // Continue search from i. 2479 while (idx <= n - m) { 2480 int j = m - 1; 2481 schar c; 2482 while (last_char != (c = subject[idx + j])) { 2483 int shift = j - CharOccurrence<schar, pchar>(c); 2484 idx += shift; 2485 if (idx > n - m) { 2486 return -1; 2487 } 2488 } 2489 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--; 2490 if (j < 0) { 2491 return idx; 2492 } else if (j < start) { 2493 // we have matched more than our tables allow us to be smart about. 2494 // Fall back on BMH shift. 2495 idx += m - 1 - CharOccurrence<schar, pchar>(last_char); 2496 } else { 2497 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift. 2498 int bc_occ = CharOccurrence<schar, pchar>(c); 2499 int shift = j - bc_occ; // Bad-char shift. 2500 if (gs_shift > shift) { 2501 shift = gs_shift; 2502 } 2503 idx += shift; 2504 } 2505 } 2506 2507 return -1; 2508} 2509 2510 2511template <typename schar> 2512static inline int SingleCharIndexOf(Vector<const schar> string, 2513 schar pattern_char, 2514 int start_index) { 2515 if (sizeof(schar) == 1) { 2516 const schar* pos = reinterpret_cast<const schar*>( 2517 memchr(string.start() + start_index, 2518 pattern_char, 2519 string.length() - start_index)); 2520 if (pos == NULL) return -1; 2521 return static_cast<int>(pos - string.start()); 2522 } 2523 for (int i = start_index, n = string.length(); i < n; i++) { 2524 if (pattern_char == string[i]) { 2525 return i; 2526 } 2527 } 2528 return -1; 2529} 2530 2531 2532template <typename schar> 2533static int SingleCharLastIndexOf(Vector<const schar> string, 2534 schar pattern_char, 2535 int start_index) { 2536 for (int i = start_index; i >= 0; i--) { 2537 if (pattern_char == string[i]) { 2538 return i; 2539 } 2540 } 2541 return -1; 2542} 2543 2544 2545// Trivial string search for shorter strings. 2546// On return, if "complete" is set to true, the return value is the 2547// final result of searching for the patter in the subject. 2548// If "complete" is set to false, the return value is the index where 2549// further checking should start, i.e., it's guaranteed that the pattern 2550// does not occur at a position prior to the returned index. 2551template <typename pchar, typename schar> 2552static int SimpleIndexOf(Vector<const schar> subject, 2553 Vector<const pchar> pattern, 2554 int idx, 2555 bool* complete) { 2556 // Badness is a count of how much work we have done. When we have 2557 // done enough work we decide it's probably worth switching to a better 2558 // algorithm. 2559 int badness = -10 - (pattern.length() << 2); 2560 2561 // We know our pattern is at least 2 characters, we cache the first so 2562 // the common case of the first character not matching is faster. 2563 pchar pattern_first_char = pattern[0]; 2564 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) { 2565 badness++; 2566 if (badness > 0) { 2567 *complete = false; 2568 return i; 2569 } 2570 if (sizeof(schar) == 1 && sizeof(pchar) == 1) { 2571 const schar* pos = reinterpret_cast<const schar*>( 2572 memchr(subject.start() + i, 2573 pattern_first_char, 2574 n - i + 1)); 2575 if (pos == NULL) { 2576 *complete = true; 2577 return -1; 2578 } 2579 i = static_cast<int>(pos - subject.start()); 2580 } else { 2581 if (subject[i] != pattern_first_char) continue; 2582 } 2583 int j = 1; 2584 do { 2585 if (pattern[j] != subject[i+j]) { 2586 break; 2587 } 2588 j++; 2589 } while (j < pattern.length()); 2590 if (j == pattern.length()) { 2591 *complete = true; 2592 return i; 2593 } 2594 badness += j; 2595 } 2596 *complete = true; 2597 return -1; 2598} 2599 2600// Simple indexOf that never bails out. For short patterns only. 2601template <typename pchar, typename schar> 2602static int SimpleIndexOf(Vector<const schar> subject, 2603 Vector<const pchar> pattern, 2604 int idx) { 2605 pchar pattern_first_char = pattern[0]; 2606 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) { 2607 if (sizeof(schar) == 1 && sizeof(pchar) == 1) { 2608 const schar* pos = reinterpret_cast<const schar*>( 2609 memchr(subject.start() + i, 2610 pattern_first_char, 2611 n - i + 1)); 2612 if (pos == NULL) return -1; 2613 i = static_cast<int>(pos - subject.start()); 2614 } else { 2615 if (subject[i] != pattern_first_char) continue; 2616 } 2617 int j = 1; 2618 do { 2619 if (pattern[j] != subject[i+j]) { 2620 break; 2621 } 2622 j++; 2623 } while (j < pattern.length()); 2624 if (j == pattern.length()) { 2625 return i; 2626 } 2627 } 2628 return -1; 2629} 2630 2631 2632// Strategy for searching for a string in another string. 2633enum StringSearchStrategy { SEARCH_FAIL, SEARCH_SHORT, SEARCH_LONG }; 2634 2635 2636template <typename pchar> 2637static inline StringSearchStrategy InitializeStringSearch( 2638 Vector<const pchar> pat, bool ascii_subject) { 2639 ASSERT(pat.length() > 1); 2640 // We have an ASCII haystack and a non-ASCII needle. Check if there 2641 // really is a non-ASCII character in the needle and bail out if there 2642 // is. 2643 if (ascii_subject && sizeof(pchar) > 1) { 2644 for (int i = 0; i < pat.length(); i++) { 2645 uc16 c = pat[i]; 2646 if (c > String::kMaxAsciiCharCode) { 2647 return SEARCH_FAIL; 2648 } 2649 } 2650 } 2651 if (pat.length() < kBMMinPatternLength) { 2652 return SEARCH_SHORT; 2653 } 2654 algorithm = SIMPLE_SEARCH; 2655 return SEARCH_LONG; 2656} 2657 2658 2659// Dispatch long needle searches to different algorithms. 2660template <typename schar, typename pchar> 2661static int ComplexIndexOf(Vector<const schar> sub, 2662 Vector<const pchar> pat, 2663 int start_index) { 2664 ASSERT(pat.length() >= kBMMinPatternLength); 2665 // Try algorithms in order of increasing setup cost and expected performance. 2666 bool complete; 2667 int idx = start_index; 2668 switch (algorithm) { 2669 case SIMPLE_SEARCH: 2670 idx = SimpleIndexOf(sub, pat, idx, &complete); 2671 if (complete) return idx; 2672 BoyerMoorePopulateBadCharTable(pat); 2673 algorithm = BOYER_MOORE_HORSPOOL; 2674 // FALLTHROUGH. 2675 case BOYER_MOORE_HORSPOOL: 2676 idx = BoyerMooreHorspool(sub, pat, idx, &complete); 2677 if (complete) return idx; 2678 // Build the Good Suffix table and continue searching. 2679 BoyerMoorePopulateGoodSuffixTable(pat); 2680 algorithm = BOYER_MOORE; 2681 // FALLTHROUGH. 2682 case BOYER_MOORE: 2683 return BoyerMooreIndexOf(sub, pat, idx); 2684 } 2685 UNREACHABLE(); 2686 return -1; 2687} 2688 2689 2690// Dispatch to different search strategies for a single search. 2691// If searching multiple times on the same needle, the search 2692// strategy should only be computed once and then dispatch to different 2693// loops. 2694template <typename schar, typename pchar> 2695static int StringSearch(Vector<const schar> sub, 2696 Vector<const pchar> pat, 2697 int start_index) { 2698 bool ascii_subject = (sizeof(schar) == 1); 2699 StringSearchStrategy strategy = InitializeStringSearch(pat, ascii_subject); 2700 switch (strategy) { 2701 case SEARCH_FAIL: return -1; 2702 case SEARCH_SHORT: return SimpleIndexOf(sub, pat, start_index); 2703 case SEARCH_LONG: return ComplexIndexOf(sub, pat, start_index); 2704 } 2705 UNREACHABLE(); 2706 return -1; 2707} 2708 2709 2710// Perform string match of pattern on subject, starting at start index. 2711// Caller must ensure that 0 <= start_index <= sub->length(), 2712// and should check that pat->length() + start_index <= sub->length() 2713int Runtime::StringMatch(Handle<String> sub, 2714 Handle<String> pat, 2715 int start_index) { 2716 ASSERT(0 <= start_index); 2717 ASSERT(start_index <= sub->length()); 2718 2719 int pattern_length = pat->length(); 2720 if (pattern_length == 0) return start_index; 2721 2722 int subject_length = sub->length(); 2723 if (start_index + pattern_length > subject_length) return -1; 2724 2725 if (!sub->IsFlat()) { 2726 FlattenString(sub); 2727 } 2728 2729 // Searching for one specific character is common. For one 2730 // character patterns linear search is necessary, so any smart 2731 // algorithm is unnecessary overhead. 2732 if (pattern_length == 1) { 2733 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid 2734 if (sub->IsAsciiRepresentation()) { 2735 uc16 pchar = pat->Get(0); 2736 if (pchar > String::kMaxAsciiCharCode) { 2737 return -1; 2738 } 2739 Vector<const char> ascii_vector = 2740 sub->ToAsciiVector().SubVector(start_index, subject_length); 2741 const void* pos = memchr(ascii_vector.start(), 2742 static_cast<const char>(pchar), 2743 static_cast<size_t>(ascii_vector.length())); 2744 if (pos == NULL) { 2745 return -1; 2746 } 2747 return static_cast<int>(reinterpret_cast<const char*>(pos) 2748 - ascii_vector.start() + start_index); 2749 } 2750 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index); 2751 } 2752 2753 if (!pat->IsFlat()) { 2754 FlattenString(pat); 2755 } 2756 2757 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid 2758 // dispatch on type of strings 2759 if (pat->IsAsciiRepresentation()) { 2760 Vector<const char> pat_vector = pat->ToAsciiVector(); 2761 if (sub->IsAsciiRepresentation()) { 2762 return StringSearch(sub->ToAsciiVector(), pat_vector, start_index); 2763 } 2764 return StringSearch(sub->ToUC16Vector(), pat_vector, start_index); 2765 } 2766 Vector<const uc16> pat_vector = pat->ToUC16Vector(); 2767 if (sub->IsAsciiRepresentation()) { 2768 return StringSearch(sub->ToAsciiVector(), pat_vector, start_index); 2769 } 2770 return StringSearch(sub->ToUC16Vector(), pat_vector, start_index); 2771} 2772 2773 2774static Object* Runtime_StringIndexOf(Arguments args) { 2775 HandleScope scope; // create a new handle scope 2776 ASSERT(args.length() == 3); 2777 2778 CONVERT_ARG_CHECKED(String, sub, 0); 2779 CONVERT_ARG_CHECKED(String, pat, 1); 2780 2781 Object* index = args[2]; 2782 uint32_t start_index; 2783 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); 2784 2785 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); 2786 int position = Runtime::StringMatch(sub, pat, start_index); 2787 return Smi::FromInt(position); 2788} 2789 2790 2791template <typename schar, typename pchar> 2792static int StringMatchBackwards(Vector<const schar> sub, 2793 Vector<const pchar> pat, 2794 int idx) { 2795 ASSERT(pat.length() >= 1); 2796 ASSERT(idx + pat.length() <= sub.length()); 2797 2798 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 2799 for (int i = 0; i < pat.length(); i++) { 2800 uc16 c = pat[i]; 2801 if (c > String::kMaxAsciiCharCode) { 2802 return -1; 2803 } 2804 } 2805 } 2806 2807 pchar pattern_first_char = pat[0]; 2808 for (int i = idx; i >= 0; i--) { 2809 if (sub[i] != pattern_first_char) continue; 2810 int j = 1; 2811 while (j < pat.length()) { 2812 if (pat[j] != sub[i+j]) { 2813 break; 2814 } 2815 j++; 2816 } 2817 if (j == pat.length()) { 2818 return i; 2819 } 2820 } 2821 return -1; 2822} 2823 2824static Object* Runtime_StringLastIndexOf(Arguments args) { 2825 HandleScope scope; // create a new handle scope 2826 ASSERT(args.length() == 3); 2827 2828 CONVERT_ARG_CHECKED(String, sub, 0); 2829 CONVERT_ARG_CHECKED(String, pat, 1); 2830 2831 Object* index = args[2]; 2832 uint32_t start_index; 2833 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); 2834 2835 uint32_t pat_length = pat->length(); 2836 uint32_t sub_length = sub->length(); 2837 2838 if (start_index + pat_length > sub_length) { 2839 start_index = sub_length - pat_length; 2840 } 2841 2842 if (pat_length == 0) { 2843 return Smi::FromInt(start_index); 2844 } 2845 2846 if (!sub->IsFlat()) { 2847 FlattenString(sub); 2848 } 2849 2850 if (pat_length == 1) { 2851 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid 2852 if (sub->IsAsciiRepresentation()) { 2853 uc16 pchar = pat->Get(0); 2854 if (pchar > String::kMaxAsciiCharCode) { 2855 return Smi::FromInt(-1); 2856 } 2857 return Smi::FromInt(SingleCharLastIndexOf(sub->ToAsciiVector(), 2858 static_cast<char>(pat->Get(0)), 2859 start_index)); 2860 } else { 2861 return Smi::FromInt(SingleCharLastIndexOf(sub->ToUC16Vector(), 2862 pat->Get(0), 2863 start_index)); 2864 } 2865 } 2866 2867 if (!pat->IsFlat()) { 2868 FlattenString(pat); 2869 } 2870 2871 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid 2872 2873 int position = -1; 2874 2875 if (pat->IsAsciiRepresentation()) { 2876 Vector<const char> pat_vector = pat->ToAsciiVector(); 2877 if (sub->IsAsciiRepresentation()) { 2878 position = StringMatchBackwards(sub->ToAsciiVector(), 2879 pat_vector, 2880 start_index); 2881 } else { 2882 position = StringMatchBackwards(sub->ToUC16Vector(), 2883 pat_vector, 2884 start_index); 2885 } 2886 } else { 2887 Vector<const uc16> pat_vector = pat->ToUC16Vector(); 2888 if (sub->IsAsciiRepresentation()) { 2889 position = StringMatchBackwards(sub->ToAsciiVector(), 2890 pat_vector, 2891 start_index); 2892 } else { 2893 position = StringMatchBackwards(sub->ToUC16Vector(), 2894 pat_vector, 2895 start_index); 2896 } 2897 } 2898 2899 return Smi::FromInt(position); 2900} 2901 2902 2903static Object* Runtime_StringLocaleCompare(Arguments args) { 2904 NoHandleAllocation ha; 2905 ASSERT(args.length() == 2); 2906 2907 CONVERT_CHECKED(String, str1, args[0]); 2908 CONVERT_CHECKED(String, str2, args[1]); 2909 2910 if (str1 == str2) return Smi::FromInt(0); // Equal. 2911 int str1_length = str1->length(); 2912 int str2_length = str2->length(); 2913 2914 // Decide trivial cases without flattening. 2915 if (str1_length == 0) { 2916 if (str2_length == 0) return Smi::FromInt(0); // Equal. 2917 return Smi::FromInt(-str2_length); 2918 } else { 2919 if (str2_length == 0) return Smi::FromInt(str1_length); 2920 } 2921 2922 int end = str1_length < str2_length ? str1_length : str2_length; 2923 2924 // No need to flatten if we are going to find the answer on the first 2925 // character. At this point we know there is at least one character 2926 // in each string, due to the trivial case handling above. 2927 int d = str1->Get(0) - str2->Get(0); 2928 if (d != 0) return Smi::FromInt(d); 2929 2930 str1->TryFlatten(); 2931 str2->TryFlatten(); 2932 2933 static StringInputBuffer buf1; 2934 static StringInputBuffer buf2; 2935 2936 buf1.Reset(str1); 2937 buf2.Reset(str2); 2938 2939 for (int i = 0; i < end; i++) { 2940 uint16_t char1 = buf1.GetNext(); 2941 uint16_t char2 = buf2.GetNext(); 2942 if (char1 != char2) return Smi::FromInt(char1 - char2); 2943 } 2944 2945 return Smi::FromInt(str1_length - str2_length); 2946} 2947 2948 2949static Object* Runtime_SubString(Arguments args) { 2950 NoHandleAllocation ha; 2951 ASSERT(args.length() == 3); 2952 2953 CONVERT_CHECKED(String, value, args[0]); 2954 Object* from = args[1]; 2955 Object* to = args[2]; 2956 int start, end; 2957 // We have a fast integer-only case here to avoid a conversion to double in 2958 // the common case where from and to are Smis. 2959 if (from->IsSmi() && to->IsSmi()) { 2960 start = Smi::cast(from)->value(); 2961 end = Smi::cast(to)->value(); 2962 } else { 2963 CONVERT_DOUBLE_CHECKED(from_number, from); 2964 CONVERT_DOUBLE_CHECKED(to_number, to); 2965 start = FastD2I(from_number); 2966 end = FastD2I(to_number); 2967 } 2968 RUNTIME_ASSERT(end >= start); 2969 RUNTIME_ASSERT(start >= 0); 2970 RUNTIME_ASSERT(end <= value->length()); 2971 Counters::sub_string_runtime.Increment(); 2972 return value->SubString(start, end); 2973} 2974 2975 2976static Object* Runtime_StringMatch(Arguments args) { 2977 ASSERT_EQ(3, args.length()); 2978 2979 CONVERT_ARG_CHECKED(String, subject, 0); 2980 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1); 2981 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2); 2982 HandleScope handles; 2983 2984 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info); 2985 2986 if (match.is_null()) { 2987 return Failure::Exception(); 2988 } 2989 if (match->IsNull()) { 2990 return Heap::null_value(); 2991 } 2992 int length = subject->length(); 2993 2994 CompilationZoneScope zone_space(DELETE_ON_EXIT); 2995 ZoneList<int> offsets(8); 2996 do { 2997 int start; 2998 int end; 2999 { 3000 AssertNoAllocation no_alloc; 3001 FixedArray* elements = FixedArray::cast(regexp_info->elements()); 3002 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value(); 3003 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value(); 3004 } 3005 offsets.Add(start); 3006 offsets.Add(end); 3007 int index = start < end ? end : end + 1; 3008 if (index > length) break; 3009 match = RegExpImpl::Exec(regexp, subject, index, regexp_info); 3010 if (match.is_null()) { 3011 return Failure::Exception(); 3012 } 3013 } while (!match->IsNull()); 3014 int matches = offsets.length() / 2; 3015 Handle<FixedArray> elements = Factory::NewFixedArray(matches); 3016 for (int i = 0; i < matches ; i++) { 3017 int from = offsets.at(i * 2); 3018 int to = offsets.at(i * 2 + 1); 3019 elements->set(i, *Factory::NewSubString(subject, from, to)); 3020 } 3021 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements); 3022 result->set_length(Smi::FromInt(matches)); 3023 return *result; 3024} 3025 3026 3027// Two smis before and after the match, for very long strings. 3028const int kMaxBuilderEntriesPerRegExpMatch = 5; 3029 3030 3031static void SetLastMatchInfoNoCaptures(Handle<String> subject, 3032 Handle<JSArray> last_match_info, 3033 int match_start, 3034 int match_end) { 3035 // Fill last_match_info with a single capture. 3036 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); 3037 AssertNoAllocation no_gc; 3038 FixedArray* elements = FixedArray::cast(last_match_info->elements()); 3039 RegExpImpl::SetLastCaptureCount(elements, 2); 3040 RegExpImpl::SetLastInput(elements, *subject); 3041 RegExpImpl::SetLastSubject(elements, *subject); 3042 RegExpImpl::SetCapture(elements, 0, match_start); 3043 RegExpImpl::SetCapture(elements, 1, match_end); 3044} 3045 3046 3047template <typename schar> 3048static bool SearchCharMultiple(Vector<schar> subject, 3049 String* pattern, 3050 schar pattern_char, 3051 FixedArrayBuilder* builder, 3052 int* match_pos) { 3053 // Position of last match. 3054 int pos = *match_pos; 3055 int subject_length = subject.length(); 3056 while (pos < subject_length) { 3057 int match_end = pos + 1; 3058 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { 3059 *match_pos = pos; 3060 return false; 3061 } 3062 int new_pos = SingleCharIndexOf(subject, pattern_char, match_end); 3063 if (new_pos >= 0) { 3064 // Match has been found. 3065 if (new_pos > match_end) { 3066 ReplacementStringBuilder::AddSubjectSlice(builder, match_end, new_pos); 3067 } 3068 pos = new_pos; 3069 builder->Add(pattern); 3070 } else { 3071 break; 3072 } 3073 } 3074 if (pos + 1 < subject_length) { 3075 ReplacementStringBuilder::AddSubjectSlice(builder, pos + 1, subject_length); 3076 } 3077 *match_pos = pos; 3078 return true; 3079} 3080 3081 3082static bool SearchCharMultiple(Handle<String> subject, 3083 Handle<String> pattern, 3084 Handle<JSArray> last_match_info, 3085 FixedArrayBuilder* builder) { 3086 ASSERT(subject->IsFlat()); 3087 ASSERT_EQ(1, pattern->length()); 3088 uc16 pattern_char = pattern->Get(0); 3089 // Treating position before first as initial "previous match position". 3090 int match_pos = -1; 3091 3092 for (;;) { // Break when search complete. 3093 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 3094 AssertNoAllocation no_gc; 3095 if (subject->IsAsciiRepresentation()) { 3096 if (pattern_char > String::kMaxAsciiCharCode) { 3097 break; 3098 } 3099 Vector<const char> subject_vector = subject->ToAsciiVector(); 3100 char pattern_ascii_char = static_cast<char>(pattern_char); 3101 bool complete = SearchCharMultiple<const char>(subject_vector, 3102 *pattern, 3103 pattern_ascii_char, 3104 builder, 3105 &match_pos); 3106 if (complete) break; 3107 } else { 3108 Vector<const uc16> subject_vector = subject->ToUC16Vector(); 3109 bool complete = SearchCharMultiple<const uc16>(subject_vector, 3110 *pattern, 3111 pattern_char, 3112 builder, 3113 &match_pos); 3114 if (complete) break; 3115 } 3116 } 3117 3118 if (match_pos >= 0) { 3119 SetLastMatchInfoNoCaptures(subject, 3120 last_match_info, 3121 match_pos, 3122 match_pos + 1); 3123 return true; 3124 } 3125 return false; // No matches at all. 3126} 3127 3128 3129template <typename schar, typename pchar> 3130static bool SearchStringMultiple(Vector<schar> subject, 3131 String* pattern, 3132 Vector<pchar> pattern_string, 3133 FixedArrayBuilder* builder, 3134 int* match_pos) { 3135 int pos = *match_pos; 3136 int subject_length = subject.length(); 3137 int pattern_length = pattern_string.length(); 3138 int max_search_start = subject_length - pattern_length; 3139 bool is_ascii = (sizeof(schar) == 1); 3140 StringSearchStrategy strategy = 3141 InitializeStringSearch(pattern_string, is_ascii); 3142 switch (strategy) { 3143 case SEARCH_FAIL: break; 3144 case SEARCH_SHORT: 3145 while (pos <= max_search_start) { 3146 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { 3147 *match_pos = pos; 3148 return false; 3149 } 3150 // Position of end of previous match. 3151 int match_end = pos + pattern_length; 3152 int new_pos = SimpleIndexOf(subject, pattern_string, match_end); 3153 if (new_pos >= 0) { 3154 // A match. 3155 if (new_pos > match_end) { 3156 ReplacementStringBuilder::AddSubjectSlice(builder, 3157 match_end, 3158 new_pos); 3159 } 3160 pos = new_pos; 3161 builder->Add(pattern); 3162 } else { 3163 break; 3164 } 3165 } 3166 break; 3167 case SEARCH_LONG: 3168 while (pos <= max_search_start) { 3169 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { 3170 *match_pos = pos; 3171 return false; 3172 } 3173 int match_end = pos + pattern_length; 3174 int new_pos = ComplexIndexOf(subject, pattern_string, match_end); 3175 if (new_pos >= 0) { 3176 // A match has been found. 3177 if (new_pos > match_end) { 3178 ReplacementStringBuilder::AddSubjectSlice(builder, 3179 match_end, 3180 new_pos); 3181 } 3182 pos = new_pos; 3183 builder->Add(pattern); 3184 } else { 3185 break; 3186 } 3187 } 3188 break; 3189 } 3190 if (pos < max_search_start) { 3191 ReplacementStringBuilder::AddSubjectSlice(builder, 3192 pos + pattern_length, 3193 subject_length); 3194 } 3195 *match_pos = pos; 3196 return true; 3197} 3198 3199 3200static bool SearchStringMultiple(Handle<String> subject, 3201 Handle<String> pattern, 3202 Handle<JSArray> last_match_info, 3203 FixedArrayBuilder* builder) { 3204 ASSERT(subject->IsFlat()); 3205 ASSERT(pattern->IsFlat()); 3206 ASSERT(pattern->length() > 1); 3207 3208 // Treating as if a previous match was before first character. 3209 int match_pos = -pattern->length(); 3210 3211 for (;;) { // Break when search complete. 3212 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 3213 AssertNoAllocation no_gc; 3214 if (subject->IsAsciiRepresentation()) { 3215 Vector<const char> subject_vector = subject->ToAsciiVector(); 3216 if (pattern->IsAsciiRepresentation()) { 3217 if (SearchStringMultiple(subject_vector, 3218 *pattern, 3219 pattern->ToAsciiVector(), 3220 builder, 3221 &match_pos)) break; 3222 } else { 3223 if (SearchStringMultiple(subject_vector, 3224 *pattern, 3225 pattern->ToUC16Vector(), 3226 builder, 3227 &match_pos)) break; 3228 } 3229 } else { 3230 Vector<const uc16> subject_vector = subject->ToUC16Vector(); 3231 if (pattern->IsAsciiRepresentation()) { 3232 if (SearchStringMultiple(subject_vector, 3233 *pattern, 3234 pattern->ToAsciiVector(), 3235 builder, 3236 &match_pos)) break; 3237 } else { 3238 if (SearchStringMultiple(subject_vector, 3239 *pattern, 3240 pattern->ToUC16Vector(), 3241 builder, 3242 &match_pos)) break; 3243 } 3244 } 3245 } 3246 3247 if (match_pos >= 0) { 3248 SetLastMatchInfoNoCaptures(subject, 3249 last_match_info, 3250 match_pos, 3251 match_pos + pattern->length()); 3252 return true; 3253 } 3254 return false; // No matches at all. 3255} 3256 3257 3258static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( 3259 Handle<String> subject, 3260 Handle<JSRegExp> regexp, 3261 Handle<JSArray> last_match_array, 3262 FixedArrayBuilder* builder) { 3263 ASSERT(subject->IsFlat()); 3264 int match_start = -1; 3265 int match_end = 0; 3266 int pos = 0; 3267 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); 3268 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; 3269 3270 OffsetsVector registers(required_registers); 3271 Vector<int> register_vector(registers.vector(), registers.length()); 3272 int subject_length = subject->length(); 3273 3274 for (;;) { // Break on failure, return on exception. 3275 RegExpImpl::IrregexpResult result = 3276 RegExpImpl::IrregexpExecOnce(regexp, 3277 subject, 3278 pos, 3279 register_vector); 3280 if (result == RegExpImpl::RE_SUCCESS) { 3281 match_start = register_vector[0]; 3282 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 3283 if (match_end < match_start) { 3284 ReplacementStringBuilder::AddSubjectSlice(builder, 3285 match_end, 3286 match_start); 3287 } 3288 match_end = register_vector[1]; 3289 HandleScope loop_scope; 3290 builder->Add(*Factory::NewSubString(subject, match_start, match_end)); 3291 if (match_start != match_end) { 3292 pos = match_end; 3293 } else { 3294 pos = match_end + 1; 3295 if (pos > subject_length) break; 3296 } 3297 } else if (result == RegExpImpl::RE_FAILURE) { 3298 break; 3299 } else { 3300 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); 3301 return result; 3302 } 3303 } 3304 3305 if (match_start >= 0) { 3306 if (match_end < subject_length) { 3307 ReplacementStringBuilder::AddSubjectSlice(builder, 3308 match_end, 3309 subject_length); 3310 } 3311 SetLastMatchInfoNoCaptures(subject, 3312 last_match_array, 3313 match_start, 3314 match_end); 3315 return RegExpImpl::RE_SUCCESS; 3316 } else { 3317 return RegExpImpl::RE_FAILURE; // No matches at all. 3318 } 3319} 3320 3321 3322static RegExpImpl::IrregexpResult SearchRegExpMultiple( 3323 Handle<String> subject, 3324 Handle<JSRegExp> regexp, 3325 Handle<JSArray> last_match_array, 3326 FixedArrayBuilder* builder) { 3327 3328 ASSERT(subject->IsFlat()); 3329 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); 3330 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; 3331 3332 OffsetsVector registers(required_registers); 3333 Vector<int> register_vector(registers.vector(), registers.length()); 3334 3335 RegExpImpl::IrregexpResult result = 3336 RegExpImpl::IrregexpExecOnce(regexp, 3337 subject, 3338 0, 3339 register_vector); 3340 3341 int capture_count = regexp->CaptureCount(); 3342 int subject_length = subject->length(); 3343 3344 // Position to search from. 3345 int pos = 0; 3346 // End of previous match. Differs from pos if match was empty. 3347 int match_end = 0; 3348 if (result == RegExpImpl::RE_SUCCESS) { 3349 // Need to keep a copy of the previous match for creating last_match_info 3350 // at the end, so we have two vectors that we swap between. 3351 OffsetsVector registers2(required_registers); 3352 Vector<int> prev_register_vector(registers2.vector(), registers2.length()); 3353 3354 do { 3355 int match_start = register_vector[0]; 3356 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 3357 if (match_end < match_start) { 3358 ReplacementStringBuilder::AddSubjectSlice(builder, 3359 match_end, 3360 match_start); 3361 } 3362 match_end = register_vector[1]; 3363 3364 { 3365 // Avoid accumulating new handles inside loop. 3366 HandleScope temp_scope; 3367 // Arguments array to replace function is match, captures, index and 3368 // subject, i.e., 3 + capture count in total. 3369 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count); 3370 elements->set(0, *Factory::NewSubString(subject, 3371 match_start, 3372 match_end)); 3373 for (int i = 1; i <= capture_count; i++) { 3374 int start = register_vector[i * 2]; 3375 if (start >= 0) { 3376 int end = register_vector[i * 2 + 1]; 3377 ASSERT(start <= end); 3378 Handle<String> substring = Factory::NewSubString(subject, 3379 start, 3380 end); 3381 elements->set(i, *substring); 3382 } else { 3383 ASSERT(register_vector[i * 2 + 1] < 0); 3384 elements->set(i, Heap::undefined_value()); 3385 } 3386 } 3387 elements->set(capture_count + 1, Smi::FromInt(match_start)); 3388 elements->set(capture_count + 2, *subject); 3389 builder->Add(*Factory::NewJSArrayWithElements(elements)); 3390 } 3391 // Swap register vectors, so the last successful match is in 3392 // prev_register_vector. 3393 Vector<int> tmp = prev_register_vector; 3394 prev_register_vector = register_vector; 3395 register_vector = tmp; 3396 3397 if (match_end > match_start) { 3398 pos = match_end; 3399 } else { 3400 pos = match_end + 1; 3401 if (pos > subject_length) { 3402 break; 3403 } 3404 } 3405 3406 result = RegExpImpl::IrregexpExecOnce(regexp, 3407 subject, 3408 pos, 3409 register_vector); 3410 } while (result == RegExpImpl::RE_SUCCESS); 3411 3412 if (result != RegExpImpl::RE_EXCEPTION) { 3413 // Finished matching, with at least one match. 3414 if (match_end < subject_length) { 3415 ReplacementStringBuilder::AddSubjectSlice(builder, 3416 match_end, 3417 subject_length); 3418 } 3419 3420 int last_match_capture_count = (capture_count + 1) * 2; 3421 int last_match_array_size = 3422 last_match_capture_count + RegExpImpl::kLastMatchOverhead; 3423 last_match_array->EnsureSize(last_match_array_size); 3424 AssertNoAllocation no_gc; 3425 FixedArray* elements = FixedArray::cast(last_match_array->elements()); 3426 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); 3427 RegExpImpl::SetLastSubject(elements, *subject); 3428 RegExpImpl::SetLastInput(elements, *subject); 3429 for (int i = 0; i < last_match_capture_count; i++) { 3430 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]); 3431 } 3432 return RegExpImpl::RE_SUCCESS; 3433 } 3434 } 3435 // No matches at all, return failure or exception result directly. 3436 return result; 3437} 3438 3439 3440static Object* Runtime_RegExpExecMultiple(Arguments args) { 3441 ASSERT(args.length() == 4); 3442 HandleScope handles; 3443 3444 CONVERT_ARG_CHECKED(String, subject, 1); 3445 if (!subject->IsFlat()) { FlattenString(subject); } 3446 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); 3447 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2); 3448 CONVERT_ARG_CHECKED(JSArray, result_array, 3); 3449 3450 ASSERT(last_match_info->HasFastElements()); 3451 ASSERT(regexp->GetFlags().is_global()); 3452 Handle<FixedArray> result_elements; 3453 if (result_array->HasFastElements()) { 3454 result_elements = 3455 Handle<FixedArray>(FixedArray::cast(result_array->elements())); 3456 } else { 3457 result_elements = Factory::NewFixedArrayWithHoles(16); 3458 } 3459 FixedArrayBuilder builder(result_elements); 3460 3461 if (regexp->TypeTag() == JSRegExp::ATOM) { 3462 Handle<String> pattern( 3463 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex))); 3464 int pattern_length = pattern->length(); 3465 if (pattern_length == 1) { 3466 if (SearchCharMultiple(subject, pattern, last_match_info, &builder)) { 3467 return *builder.ToJSArray(result_array); 3468 } 3469 return Heap::null_value(); 3470 } 3471 3472 if (!pattern->IsFlat()) FlattenString(pattern); 3473 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) { 3474 return *builder.ToJSArray(result_array); 3475 } 3476 return Heap::null_value(); 3477 } 3478 3479 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); 3480 3481 RegExpImpl::IrregexpResult result; 3482 if (regexp->CaptureCount() == 0) { 3483 result = SearchRegExpNoCaptureMultiple(subject, 3484 regexp, 3485 last_match_info, 3486 &builder); 3487 } else { 3488 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder); 3489 } 3490 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); 3491 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value(); 3492 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); 3493 return Failure::Exception(); 3494} 3495 3496 3497static Object* Runtime_NumberToRadixString(Arguments args) { 3498 NoHandleAllocation ha; 3499 ASSERT(args.length() == 2); 3500 3501 // Fast case where the result is a one character string. 3502 if (args[0]->IsSmi() && args[1]->IsSmi()) { 3503 int value = Smi::cast(args[0])->value(); 3504 int radix = Smi::cast(args[1])->value(); 3505 if (value >= 0 && value < radix) { 3506 RUNTIME_ASSERT(radix <= 36); 3507 // Character array used for conversion. 3508 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 3509 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]); 3510 } 3511 } 3512 3513 // Slow case. 3514 CONVERT_DOUBLE_CHECKED(value, args[0]); 3515 if (isnan(value)) { 3516 return Heap::AllocateStringFromAscii(CStrVector("NaN")); 3517 } 3518 if (isinf(value)) { 3519 if (value < 0) { 3520 return Heap::AllocateStringFromAscii(CStrVector("-Infinity")); 3521 } 3522 return Heap::AllocateStringFromAscii(CStrVector("Infinity")); 3523 } 3524 CONVERT_DOUBLE_CHECKED(radix_number, args[1]); 3525 int radix = FastD2I(radix_number); 3526 RUNTIME_ASSERT(2 <= radix && radix <= 36); 3527 char* str = DoubleToRadixCString(value, radix); 3528 Object* result = Heap::AllocateStringFromAscii(CStrVector(str)); 3529 DeleteArray(str); 3530 return result; 3531} 3532 3533 3534static Object* Runtime_NumberToFixed(Arguments args) { 3535 NoHandleAllocation ha; 3536 ASSERT(args.length() == 2); 3537 3538 CONVERT_DOUBLE_CHECKED(value, args[0]); 3539 if (isnan(value)) { 3540 return Heap::AllocateStringFromAscii(CStrVector("NaN")); 3541 } 3542 if (isinf(value)) { 3543 if (value < 0) { 3544 return Heap::AllocateStringFromAscii(CStrVector("-Infinity")); 3545 } 3546 return Heap::AllocateStringFromAscii(CStrVector("Infinity")); 3547 } 3548 CONVERT_DOUBLE_CHECKED(f_number, args[1]); 3549 int f = FastD2I(f_number); 3550 RUNTIME_ASSERT(f >= 0); 3551 char* str = DoubleToFixedCString(value, f); 3552 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); 3553 DeleteArray(str); 3554 return res; 3555} 3556 3557 3558static Object* Runtime_NumberToExponential(Arguments args) { 3559 NoHandleAllocation ha; 3560 ASSERT(args.length() == 2); 3561 3562 CONVERT_DOUBLE_CHECKED(value, args[0]); 3563 if (isnan(value)) { 3564 return Heap::AllocateStringFromAscii(CStrVector("NaN")); 3565 } 3566 if (isinf(value)) { 3567 if (value < 0) { 3568 return Heap::AllocateStringFromAscii(CStrVector("-Infinity")); 3569 } 3570 return Heap::AllocateStringFromAscii(CStrVector("Infinity")); 3571 } 3572 CONVERT_DOUBLE_CHECKED(f_number, args[1]); 3573 int f = FastD2I(f_number); 3574 RUNTIME_ASSERT(f >= -1 && f <= 20); 3575 char* str = DoubleToExponentialCString(value, f); 3576 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); 3577 DeleteArray(str); 3578 return res; 3579} 3580 3581 3582static Object* Runtime_NumberToPrecision(Arguments args) { 3583 NoHandleAllocation ha; 3584 ASSERT(args.length() == 2); 3585 3586 CONVERT_DOUBLE_CHECKED(value, args[0]); 3587 if (isnan(value)) { 3588 return Heap::AllocateStringFromAscii(CStrVector("NaN")); 3589 } 3590 if (isinf(value)) { 3591 if (value < 0) { 3592 return Heap::AllocateStringFromAscii(CStrVector("-Infinity")); 3593 } 3594 return Heap::AllocateStringFromAscii(CStrVector("Infinity")); 3595 } 3596 CONVERT_DOUBLE_CHECKED(f_number, args[1]); 3597 int f = FastD2I(f_number); 3598 RUNTIME_ASSERT(f >= 1 && f <= 21); 3599 char* str = DoubleToPrecisionCString(value, f); 3600 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); 3601 DeleteArray(str); 3602 return res; 3603} 3604 3605 3606// Returns a single character string where first character equals 3607// string->Get(index). 3608static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { 3609 if (index < static_cast<uint32_t>(string->length())) { 3610 string->TryFlatten(); 3611 return LookupSingleCharacterStringFromCode( 3612 string->Get(index)); 3613 } 3614 return Execution::CharAt(string, index); 3615} 3616 3617 3618Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { 3619 // Handle [] indexing on Strings 3620 if (object->IsString()) { 3621 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); 3622 if (!result->IsUndefined()) return *result; 3623 } 3624 3625 // Handle [] indexing on String objects 3626 if (object->IsStringObjectWithCharacterAt(index)) { 3627 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 3628 Handle<Object> result = 3629 GetCharAt(Handle<String>(String::cast(js_value->value())), index); 3630 if (!result->IsUndefined()) return *result; 3631 } 3632 3633 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 3634 Handle<Object> prototype = GetPrototype(object); 3635 return prototype->GetElement(index); 3636 } 3637 3638 return GetElement(object, index); 3639} 3640 3641 3642Object* Runtime::GetElement(Handle<Object> object, uint32_t index) { 3643 return object->GetElement(index); 3644} 3645 3646 3647Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) { 3648 HandleScope scope; 3649 3650 if (object->IsUndefined() || object->IsNull()) { 3651 Handle<Object> args[2] = { key, object }; 3652 Handle<Object> error = 3653 Factory::NewTypeError("non_object_property_load", 3654 HandleVector(args, 2)); 3655 return Top::Throw(*error); 3656 } 3657 3658 // Check if the given key is an array index. 3659 uint32_t index; 3660 if (Array::IndexFromObject(*key, &index)) { 3661 return GetElementOrCharAt(object, index); 3662 } 3663 3664 // Convert the key to a string - possibly by calling back into JavaScript. 3665 Handle<String> name; 3666 if (key->IsString()) { 3667 name = Handle<String>::cast(key); 3668 } else { 3669 bool has_pending_exception = false; 3670 Handle<Object> converted = 3671 Execution::ToString(key, &has_pending_exception); 3672 if (has_pending_exception) return Failure::Exception(); 3673 name = Handle<String>::cast(converted); 3674 } 3675 3676 // Check if the name is trivially convertible to an index and get 3677 // the element if so. 3678 if (name->AsArrayIndex(&index)) { 3679 return GetElementOrCharAt(object, index); 3680 } else { 3681 PropertyAttributes attr; 3682 return object->GetProperty(*name, &attr); 3683 } 3684} 3685 3686 3687static Object* Runtime_GetProperty(Arguments args) { 3688 NoHandleAllocation ha; 3689 ASSERT(args.length() == 2); 3690 3691 Handle<Object> object = args.at<Object>(0); 3692 Handle<Object> key = args.at<Object>(1); 3693 3694 return Runtime::GetObjectProperty(object, key); 3695} 3696 3697 3698// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric. 3699static Object* Runtime_KeyedGetProperty(Arguments args) { 3700 NoHandleAllocation ha; 3701 ASSERT(args.length() == 2); 3702 3703 // Fast cases for getting named properties of the receiver JSObject 3704 // itself. 3705 // 3706 // The global proxy objects has to be excluded since LocalLookup on 3707 // the global proxy object can return a valid result even though the 3708 // global proxy object never has properties. This is the case 3709 // because the global proxy object forwards everything to its hidden 3710 // prototype including local lookups. 3711 // 3712 // Additionally, we need to make sure that we do not cache results 3713 // for objects that require access checks. 3714 if (args[0]->IsJSObject() && 3715 !args[0]->IsJSGlobalProxy() && 3716 !args[0]->IsAccessCheckNeeded() && 3717 args[1]->IsString()) { 3718 JSObject* receiver = JSObject::cast(args[0]); 3719 String* key = String::cast(args[1]); 3720 if (receiver->HasFastProperties()) { 3721 // Attempt to use lookup cache. 3722 Map* receiver_map = receiver->map(); 3723 int offset = KeyedLookupCache::Lookup(receiver_map, key); 3724 if (offset != -1) { 3725 Object* value = receiver->FastPropertyAt(offset); 3726 return value->IsTheHole() ? Heap::undefined_value() : value; 3727 } 3728 // Lookup cache miss. Perform lookup and update the cache if appropriate. 3729 LookupResult result; 3730 receiver->LocalLookup(key, &result); 3731 if (result.IsProperty() && result.type() == FIELD) { 3732 int offset = result.GetFieldIndex(); 3733 KeyedLookupCache::Update(receiver_map, key, offset); 3734 return receiver->FastPropertyAt(offset); 3735 } 3736 } else { 3737 // Attempt dictionary lookup. 3738 StringDictionary* dictionary = receiver->property_dictionary(); 3739 int entry = dictionary->FindEntry(key); 3740 if ((entry != StringDictionary::kNotFound) && 3741 (dictionary->DetailsAt(entry).type() == NORMAL)) { 3742 Object* value = dictionary->ValueAt(entry); 3743 if (!receiver->IsGlobalObject()) return value; 3744 value = JSGlobalPropertyCell::cast(value)->value(); 3745 if (!value->IsTheHole()) return value; 3746 // If value is the hole do the general lookup. 3747 } 3748 } 3749 } else if (args[0]->IsString() && args[1]->IsSmi()) { 3750 // Fast case for string indexing using [] with a smi index. 3751 HandleScope scope; 3752 Handle<String> str = args.at<String>(0); 3753 int index = Smi::cast(args[1])->value(); 3754 Handle<Object> result = GetCharAt(str, index); 3755 return *result; 3756 } 3757 3758 // Fall back to GetObjectProperty. 3759 return Runtime::GetObjectProperty(args.at<Object>(0), 3760 args.at<Object>(1)); 3761} 3762 3763 3764static Object* Runtime_DefineOrRedefineAccessorProperty(Arguments args) { 3765 ASSERT(args.length() == 5); 3766 HandleScope scope; 3767 CONVERT_ARG_CHECKED(JSObject, obj, 0); 3768 CONVERT_CHECKED(String, name, args[1]); 3769 CONVERT_CHECKED(Smi, flag_setter, args[2]); 3770 CONVERT_CHECKED(JSFunction, fun, args[3]); 3771 CONVERT_CHECKED(Smi, flag_attr, args[4]); 3772 int unchecked = flag_attr->value(); 3773 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 3774 RUNTIME_ASSERT(!obj->IsNull()); 3775 LookupResult result; 3776 obj->LocalLookupRealNamedProperty(name, &result); 3777 3778 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 3779 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION 3780 // delete it to avoid running into trouble in DefineAccessor, which 3781 // handles this incorrectly if the property is readonly (does nothing) 3782 if (result.IsProperty() && 3783 (result.type() == FIELD || result.type() == NORMAL 3784 || result.type() == CONSTANT_FUNCTION)) { 3785 obj->DeleteProperty(name, JSObject::NORMAL_DELETION); 3786 } 3787 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr); 3788} 3789 3790static Object* Runtime_DefineOrRedefineDataProperty(Arguments args) { 3791 ASSERT(args.length() == 4); 3792 HandleScope scope; 3793 CONVERT_ARG_CHECKED(JSObject, js_object, 0); 3794 CONVERT_ARG_CHECKED(String, name, 1); 3795 Handle<Object> obj_value = args.at<Object>(2); 3796 3797 CONVERT_CHECKED(Smi, flag, args[3]); 3798 int unchecked = flag->value(); 3799 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 3800 3801 LookupResult result; 3802 js_object->LocalLookupRealNamedProperty(*name, &result); 3803 3804 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 3805 3806 // Take special care when attributes are different and there is already 3807 // a property. For simplicity we normalize the property which enables us 3808 // to not worry about changing the instance_descriptor and creating a new 3809 // map. The current version of SetObjectProperty does not handle attributes 3810 // correctly in the case where a property is a field and is reset with 3811 // new attributes. 3812 if (result.IsProperty() && attr != result.GetAttributes()) { 3813 // New attributes - normalize to avoid writing to instance descriptor 3814 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 3815 // Use IgnoreAttributes version since a readonly property may be 3816 // overridden and SetProperty does not allow this. 3817 return js_object->IgnoreAttributesAndSetLocalProperty(*name, 3818 *obj_value, 3819 attr); 3820 } 3821 return Runtime::SetObjectProperty(js_object, name, obj_value, attr); 3822} 3823 3824 3825Object* Runtime::SetObjectProperty(Handle<Object> object, 3826 Handle<Object> key, 3827 Handle<Object> value, 3828 PropertyAttributes attr) { 3829 HandleScope scope; 3830 3831 if (object->IsUndefined() || object->IsNull()) { 3832 Handle<Object> args[2] = { key, object }; 3833 Handle<Object> error = 3834 Factory::NewTypeError("non_object_property_store", 3835 HandleVector(args, 2)); 3836 return Top::Throw(*error); 3837 } 3838 3839 // If the object isn't a JavaScript object, we ignore the store. 3840 if (!object->IsJSObject()) return *value; 3841 3842 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 3843 3844 // Check if the given key is an array index. 3845 uint32_t index; 3846 if (Array::IndexFromObject(*key, &index)) { 3847 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 3848 // of a string using [] notation. We need to support this too in 3849 // JavaScript. 3850 // In the case of a String object we just need to redirect the assignment to 3851 // the underlying string if the index is in range. Since the underlying 3852 // string does nothing with the assignment then we can ignore such 3853 // assignments. 3854 if (js_object->IsStringObjectWithCharacterAt(index)) { 3855 return *value; 3856 } 3857 3858 Handle<Object> result = SetElement(js_object, index, value); 3859 if (result.is_null()) return Failure::Exception(); 3860 return *value; 3861 } 3862 3863 if (key->IsString()) { 3864 Handle<Object> result; 3865 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { 3866 result = SetElement(js_object, index, value); 3867 } else { 3868 Handle<String> key_string = Handle<String>::cast(key); 3869 key_string->TryFlatten(); 3870 result = SetProperty(js_object, key_string, value, attr); 3871 } 3872 if (result.is_null()) return Failure::Exception(); 3873 return *value; 3874 } 3875 3876 // Call-back into JavaScript to convert the key to a string. 3877 bool has_pending_exception = false; 3878 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 3879 if (has_pending_exception) return Failure::Exception(); 3880 Handle<String> name = Handle<String>::cast(converted); 3881 3882 if (name->AsArrayIndex(&index)) { 3883 return js_object->SetElement(index, *value); 3884 } else { 3885 return js_object->SetProperty(*name, *value, attr); 3886 } 3887} 3888 3889 3890Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object, 3891 Handle<Object> key, 3892 Handle<Object> value, 3893 PropertyAttributes attr) { 3894 HandleScope scope; 3895 3896 // Check if the given key is an array index. 3897 uint32_t index; 3898 if (Array::IndexFromObject(*key, &index)) { 3899 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 3900 // of a string using [] notation. We need to support this too in 3901 // JavaScript. 3902 // In the case of a String object we just need to redirect the assignment to 3903 // the underlying string if the index is in range. Since the underlying 3904 // string does nothing with the assignment then we can ignore such 3905 // assignments. 3906 if (js_object->IsStringObjectWithCharacterAt(index)) { 3907 return *value; 3908 } 3909 3910 return js_object->SetElement(index, *value); 3911 } 3912 3913 if (key->IsString()) { 3914 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { 3915 return js_object->SetElement(index, *value); 3916 } else { 3917 Handle<String> key_string = Handle<String>::cast(key); 3918 key_string->TryFlatten(); 3919 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string, 3920 *value, 3921 attr); 3922 } 3923 } 3924 3925 // Call-back into JavaScript to convert the key to a string. 3926 bool has_pending_exception = false; 3927 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 3928 if (has_pending_exception) return Failure::Exception(); 3929 Handle<String> name = Handle<String>::cast(converted); 3930 3931 if (name->AsArrayIndex(&index)) { 3932 return js_object->SetElement(index, *value); 3933 } else { 3934 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr); 3935 } 3936} 3937 3938 3939Object* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object, 3940 Handle<Object> key) { 3941 HandleScope scope; 3942 3943 // Check if the given key is an array index. 3944 uint32_t index; 3945 if (Array::IndexFromObject(*key, &index)) { 3946 // In Firefox/SpiderMonkey, Safari and Opera you can access the 3947 // characters of a string using [] notation. In the case of a 3948 // String object we just need to redirect the deletion to the 3949 // underlying string if the index is in range. Since the 3950 // underlying string does nothing with the deletion, we can ignore 3951 // such deletions. 3952 if (js_object->IsStringObjectWithCharacterAt(index)) { 3953 return Heap::true_value(); 3954 } 3955 3956 return js_object->DeleteElement(index, JSObject::FORCE_DELETION); 3957 } 3958 3959 Handle<String> key_string; 3960 if (key->IsString()) { 3961 key_string = Handle<String>::cast(key); 3962 } else { 3963 // Call-back into JavaScript to convert the key to a string. 3964 bool has_pending_exception = false; 3965 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 3966 if (has_pending_exception) return Failure::Exception(); 3967 key_string = Handle<String>::cast(converted); 3968 } 3969 3970 key_string->TryFlatten(); 3971 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); 3972} 3973 3974 3975static Object* Runtime_SetProperty(Arguments args) { 3976 NoHandleAllocation ha; 3977 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); 3978 3979 Handle<Object> object = args.at<Object>(0); 3980 Handle<Object> key = args.at<Object>(1); 3981 Handle<Object> value = args.at<Object>(2); 3982 3983 // Compute attributes. 3984 PropertyAttributes attributes = NONE; 3985 if (args.length() == 4) { 3986 CONVERT_CHECKED(Smi, value_obj, args[3]); 3987 int unchecked_value = value_obj->value(); 3988 // Only attribute bits should be set. 3989 RUNTIME_ASSERT( 3990 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 3991 attributes = static_cast<PropertyAttributes>(unchecked_value); 3992 } 3993 return Runtime::SetObjectProperty(object, key, value, attributes); 3994} 3995 3996 3997// Set a local property, even if it is READ_ONLY. If the property does not 3998// exist, it will be added with attributes NONE. 3999static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) { 4000 NoHandleAllocation ha; 4001 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); 4002 CONVERT_CHECKED(JSObject, object, args[0]); 4003 CONVERT_CHECKED(String, name, args[1]); 4004 // Compute attributes. 4005 PropertyAttributes attributes = NONE; 4006 if (args.length() == 4) { 4007 CONVERT_CHECKED(Smi, value_obj, args[3]); 4008 int unchecked_value = value_obj->value(); 4009 // Only attribute bits should be set. 4010 RUNTIME_ASSERT( 4011 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 4012 attributes = static_cast<PropertyAttributes>(unchecked_value); 4013 } 4014 4015 return object-> 4016 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes); 4017} 4018 4019 4020static Object* Runtime_DeleteProperty(Arguments args) { 4021 NoHandleAllocation ha; 4022 ASSERT(args.length() == 2); 4023 4024 CONVERT_CHECKED(JSObject, object, args[0]); 4025 CONVERT_CHECKED(String, key, args[1]); 4026 return object->DeleteProperty(key, JSObject::NORMAL_DELETION); 4027} 4028 4029 4030static Object* HasLocalPropertyImplementation(Handle<JSObject> object, 4031 Handle<String> key) { 4032 if (object->HasLocalProperty(*key)) return Heap::true_value(); 4033 // Handle hidden prototypes. If there's a hidden prototype above this thing 4034 // then we have to check it for properties, because they are supposed to 4035 // look like they are on this object. 4036 Handle<Object> proto(object->GetPrototype()); 4037 if (proto->IsJSObject() && 4038 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { 4039 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key); 4040 } 4041 return Heap::false_value(); 4042} 4043 4044 4045static Object* Runtime_HasLocalProperty(Arguments args) { 4046 NoHandleAllocation ha; 4047 ASSERT(args.length() == 2); 4048 CONVERT_CHECKED(String, key, args[1]); 4049 4050 Object* obj = args[0]; 4051 // Only JS objects can have properties. 4052 if (obj->IsJSObject()) { 4053 JSObject* object = JSObject::cast(obj); 4054 // Fast case - no interceptors. 4055 if (object->HasRealNamedProperty(key)) return Heap::true_value(); 4056 // Slow case. Either it's not there or we have an interceptor. We should 4057 // have handles for this kind of deal. 4058 HandleScope scope; 4059 return HasLocalPropertyImplementation(Handle<JSObject>(object), 4060 Handle<String>(key)); 4061 } else if (obj->IsString()) { 4062 // Well, there is one exception: Handle [] on strings. 4063 uint32_t index; 4064 if (key->AsArrayIndex(&index)) { 4065 String* string = String::cast(obj); 4066 if (index < static_cast<uint32_t>(string->length())) 4067 return Heap::true_value(); 4068 } 4069 } 4070 return Heap::false_value(); 4071} 4072 4073 4074static Object* Runtime_HasProperty(Arguments args) { 4075 NoHandleAllocation na; 4076 ASSERT(args.length() == 2); 4077 4078 // Only JS objects can have properties. 4079 if (args[0]->IsJSObject()) { 4080 JSObject* object = JSObject::cast(args[0]); 4081 CONVERT_CHECKED(String, key, args[1]); 4082 if (object->HasProperty(key)) return Heap::true_value(); 4083 } 4084 return Heap::false_value(); 4085} 4086 4087 4088static Object* Runtime_HasElement(Arguments args) { 4089 NoHandleAllocation na; 4090 ASSERT(args.length() == 2); 4091 4092 // Only JS objects can have elements. 4093 if (args[0]->IsJSObject()) { 4094 JSObject* object = JSObject::cast(args[0]); 4095 CONVERT_CHECKED(Smi, index_obj, args[1]); 4096 uint32_t index = index_obj->value(); 4097 if (object->HasElement(index)) return Heap::true_value(); 4098 } 4099 return Heap::false_value(); 4100} 4101 4102 4103static Object* Runtime_IsPropertyEnumerable(Arguments args) { 4104 NoHandleAllocation ha; 4105 ASSERT(args.length() == 2); 4106 4107 CONVERT_CHECKED(JSObject, object, args[0]); 4108 CONVERT_CHECKED(String, key, args[1]); 4109 4110 uint32_t index; 4111 if (key->AsArrayIndex(&index)) { 4112 return Heap::ToBoolean(object->HasElement(index)); 4113 } 4114 4115 PropertyAttributes att = object->GetLocalPropertyAttribute(key); 4116 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0); 4117} 4118 4119 4120static Object* Runtime_GetPropertyNames(Arguments args) { 4121 HandleScope scope; 4122 ASSERT(args.length() == 1); 4123 CONVERT_ARG_CHECKED(JSObject, object, 0); 4124 return *GetKeysFor(object); 4125} 4126 4127 4128// Returns either a FixedArray as Runtime_GetPropertyNames, 4129// or, if the given object has an enum cache that contains 4130// all enumerable properties of the object and its prototypes 4131// have none, the map of the object. This is used to speed up 4132// the check for deletions during a for-in. 4133static Object* Runtime_GetPropertyNamesFast(Arguments args) { 4134 ASSERT(args.length() == 1); 4135 4136 CONVERT_CHECKED(JSObject, raw_object, args[0]); 4137 4138 if (raw_object->IsSimpleEnum()) return raw_object->map(); 4139 4140 HandleScope scope; 4141 Handle<JSObject> object(raw_object); 4142 Handle<FixedArray> content = GetKeysInFixedArrayFor(object, 4143 INCLUDE_PROTOS); 4144 4145 // Test again, since cache may have been built by preceding call. 4146 if (object->IsSimpleEnum()) return object->map(); 4147 4148 return *content; 4149} 4150 4151 4152// Find the length of the prototype chain that is to to handled as one. If a 4153// prototype object is hidden it is to be viewed as part of the the object it 4154// is prototype for. 4155static int LocalPrototypeChainLength(JSObject* obj) { 4156 int count = 1; 4157 Object* proto = obj->GetPrototype(); 4158 while (proto->IsJSObject() && 4159 JSObject::cast(proto)->map()->is_hidden_prototype()) { 4160 count++; 4161 proto = JSObject::cast(proto)->GetPrototype(); 4162 } 4163 return count; 4164} 4165 4166 4167// Return the names of the local named properties. 4168// args[0]: object 4169static Object* Runtime_GetLocalPropertyNames(Arguments args) { 4170 HandleScope scope; 4171 ASSERT(args.length() == 1); 4172 if (!args[0]->IsJSObject()) { 4173 return Heap::undefined_value(); 4174 } 4175 CONVERT_ARG_CHECKED(JSObject, obj, 0); 4176 4177 // Skip the global proxy as it has no properties and always delegates to the 4178 // real global object. 4179 if (obj->IsJSGlobalProxy()) { 4180 // Only collect names if access is permitted. 4181 if (obj->IsAccessCheckNeeded() && 4182 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) { 4183 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS); 4184 return *Factory::NewJSArray(0); 4185 } 4186 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 4187 } 4188 4189 // Find the number of objects making up this. 4190 int length = LocalPrototypeChainLength(*obj); 4191 4192 // Find the number of local properties for each of the objects. 4193 ScopedVector<int> local_property_count(length); 4194 int total_property_count = 0; 4195 Handle<JSObject> jsproto = obj; 4196 for (int i = 0; i < length; i++) { 4197 // Only collect names if access is permitted. 4198 if (jsproto->IsAccessCheckNeeded() && 4199 !Top::MayNamedAccess(*jsproto, 4200 Heap::undefined_value(), 4201 v8::ACCESS_KEYS)) { 4202 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS); 4203 return *Factory::NewJSArray(0); 4204 } 4205 int n; 4206 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE)); 4207 local_property_count[i] = n; 4208 total_property_count += n; 4209 if (i < length - 1) { 4210 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 4211 } 4212 } 4213 4214 // Allocate an array with storage for all the property names. 4215 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count); 4216 4217 // Get the property names. 4218 jsproto = obj; 4219 int proto_with_hidden_properties = 0; 4220 for (int i = 0; i < length; i++) { 4221 jsproto->GetLocalPropertyNames(*names, 4222 i == 0 ? 0 : local_property_count[i - 1]); 4223 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) { 4224 proto_with_hidden_properties++; 4225 } 4226 if (i < length - 1) { 4227 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 4228 } 4229 } 4230 4231 // Filter out name of hidden propeties object. 4232 if (proto_with_hidden_properties > 0) { 4233 Handle<FixedArray> old_names = names; 4234 names = Factory::NewFixedArray( 4235 names->length() - proto_with_hidden_properties); 4236 int dest_pos = 0; 4237 for (int i = 0; i < total_property_count; i++) { 4238 Object* name = old_names->get(i); 4239 if (name == Heap::hidden_symbol()) { 4240 continue; 4241 } 4242 names->set(dest_pos++, name); 4243 } 4244 } 4245 4246 return *Factory::NewJSArrayWithElements(names); 4247} 4248 4249 4250// Return the names of the local indexed properties. 4251// args[0]: object 4252static Object* Runtime_GetLocalElementNames(Arguments args) { 4253 HandleScope scope; 4254 ASSERT(args.length() == 1); 4255 if (!args[0]->IsJSObject()) { 4256 return Heap::undefined_value(); 4257 } 4258 CONVERT_ARG_CHECKED(JSObject, obj, 0); 4259 4260 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE)); 4261 Handle<FixedArray> names = Factory::NewFixedArray(n); 4262 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE)); 4263 return *Factory::NewJSArrayWithElements(names); 4264} 4265 4266 4267// Return information on whether an object has a named or indexed interceptor. 4268// args[0]: object 4269static Object* Runtime_GetInterceptorInfo(Arguments args) { 4270 HandleScope scope; 4271 ASSERT(args.length() == 1); 4272 if (!args[0]->IsJSObject()) { 4273 return Smi::FromInt(0); 4274 } 4275 CONVERT_ARG_CHECKED(JSObject, obj, 0); 4276 4277 int result = 0; 4278 if (obj->HasNamedInterceptor()) result |= 2; 4279 if (obj->HasIndexedInterceptor()) result |= 1; 4280 4281 return Smi::FromInt(result); 4282} 4283 4284 4285// Return property names from named interceptor. 4286// args[0]: object 4287static Object* Runtime_GetNamedInterceptorPropertyNames(Arguments args) { 4288 HandleScope scope; 4289 ASSERT(args.length() == 1); 4290 CONVERT_ARG_CHECKED(JSObject, obj, 0); 4291 4292 if (obj->HasNamedInterceptor()) { 4293 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj); 4294 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 4295 } 4296 return Heap::undefined_value(); 4297} 4298 4299 4300// Return element names from indexed interceptor. 4301// args[0]: object 4302static Object* Runtime_GetIndexedInterceptorElementNames(Arguments args) { 4303 HandleScope scope; 4304 ASSERT(args.length() == 1); 4305 CONVERT_ARG_CHECKED(JSObject, obj, 0); 4306 4307 if (obj->HasIndexedInterceptor()) { 4308 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj); 4309 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 4310 } 4311 return Heap::undefined_value(); 4312} 4313 4314 4315static Object* Runtime_LocalKeys(Arguments args) { 4316 ASSERT_EQ(args.length(), 1); 4317 CONVERT_CHECKED(JSObject, raw_object, args[0]); 4318 HandleScope scope; 4319 Handle<JSObject> object(raw_object); 4320 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object, 4321 LOCAL_ONLY); 4322 // Some fast paths through GetKeysInFixedArrayFor reuse a cached 4323 // property array and since the result is mutable we have to create 4324 // a fresh clone on each invocation. 4325 int length = contents->length(); 4326 Handle<FixedArray> copy = Factory::NewFixedArray(length); 4327 for (int i = 0; i < length; i++) { 4328 Object* entry = contents->get(i); 4329 if (entry->IsString()) { 4330 copy->set(i, entry); 4331 } else { 4332 ASSERT(entry->IsNumber()); 4333 HandleScope scope; 4334 Handle<Object> entry_handle(entry); 4335 Handle<Object> entry_str = Factory::NumberToString(entry_handle); 4336 copy->set(i, *entry_str); 4337 } 4338 } 4339 return *Factory::NewJSArrayWithElements(copy); 4340} 4341 4342 4343static Object* Runtime_GetArgumentsProperty(Arguments args) { 4344 NoHandleAllocation ha; 4345 ASSERT(args.length() == 1); 4346 4347 // Compute the frame holding the arguments. 4348 JavaScriptFrameIterator it; 4349 it.AdvanceToArgumentsFrame(); 4350 JavaScriptFrame* frame = it.frame(); 4351 4352 // Get the actual number of provided arguments. 4353 const uint32_t n = frame->GetProvidedParametersCount(); 4354 4355 // Try to convert the key to an index. If successful and within 4356 // index return the the argument from the frame. 4357 uint32_t index; 4358 if (Array::IndexFromObject(args[0], &index) && index < n) { 4359 return frame->GetParameter(index); 4360 } 4361 4362 // Convert the key to a string. 4363 HandleScope scope; 4364 bool exception = false; 4365 Handle<Object> converted = 4366 Execution::ToString(args.at<Object>(0), &exception); 4367 if (exception) return Failure::Exception(); 4368 Handle<String> key = Handle<String>::cast(converted); 4369 4370 // Try to convert the string key into an array index. 4371 if (key->AsArrayIndex(&index)) { 4372 if (index < n) { 4373 return frame->GetParameter(index); 4374 } else { 4375 return Top::initial_object_prototype()->GetElement(index); 4376 } 4377 } 4378 4379 // Handle special arguments properties. 4380 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n); 4381 if (key->Equals(Heap::callee_symbol())) return frame->function(); 4382 4383 // Lookup in the initial Object.prototype object. 4384 return Top::initial_object_prototype()->GetProperty(*key); 4385} 4386 4387 4388static Object* Runtime_ToFastProperties(Arguments args) { 4389 HandleScope scope; 4390 4391 ASSERT(args.length() == 1); 4392 Handle<Object> object = args.at<Object>(0); 4393 if (object->IsJSObject()) { 4394 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 4395 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) { 4396 js_object->TransformToFastProperties(0); 4397 } 4398 } 4399 return *object; 4400} 4401 4402 4403static Object* Runtime_ToSlowProperties(Arguments args) { 4404 HandleScope scope; 4405 4406 ASSERT(args.length() == 1); 4407 Handle<Object> object = args.at<Object>(0); 4408 if (object->IsJSObject()) { 4409 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 4410 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 4411 } 4412 return *object; 4413} 4414 4415 4416static Object* Runtime_ToBool(Arguments args) { 4417 NoHandleAllocation ha; 4418 ASSERT(args.length() == 1); 4419 4420 return args[0]->ToBoolean(); 4421} 4422 4423 4424// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). 4425// Possible optimizations: put the type string into the oddballs. 4426static Object* Runtime_Typeof(Arguments args) { 4427 NoHandleAllocation ha; 4428 4429 Object* obj = args[0]; 4430 if (obj->IsNumber()) return Heap::number_symbol(); 4431 HeapObject* heap_obj = HeapObject::cast(obj); 4432 4433 // typeof an undetectable object is 'undefined' 4434 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol(); 4435 4436 InstanceType instance_type = heap_obj->map()->instance_type(); 4437 if (instance_type < FIRST_NONSTRING_TYPE) { 4438 return Heap::string_symbol(); 4439 } 4440 4441 switch (instance_type) { 4442 case ODDBALL_TYPE: 4443 if (heap_obj->IsTrue() || heap_obj->IsFalse()) { 4444 return Heap::boolean_symbol(); 4445 } 4446 if (heap_obj->IsNull()) { 4447 return Heap::object_symbol(); 4448 } 4449 ASSERT(heap_obj->IsUndefined()); 4450 return Heap::undefined_symbol(); 4451 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE: 4452 return Heap::function_symbol(); 4453 default: 4454 // For any kind of object not handled above, the spec rule for 4455 // host objects gives that it is okay to return "object" 4456 return Heap::object_symbol(); 4457 } 4458} 4459 4460 4461static bool AreDigits(const char*s, int from, int to) { 4462 for (int i = from; i < to; i++) { 4463 if (s[i] < '0' || s[i] > '9') return false; 4464 } 4465 4466 return true; 4467} 4468 4469 4470static int ParseDecimalInteger(const char*s, int from, int to) { 4471 ASSERT(to - from < 10); // Overflow is not possible. 4472 ASSERT(from < to); 4473 int d = s[from] - '0'; 4474 4475 for (int i = from + 1; i < to; i++) { 4476 d = 10 * d + (s[i] - '0'); 4477 } 4478 4479 return d; 4480} 4481 4482 4483static Object* Runtime_StringToNumber(Arguments args) { 4484 NoHandleAllocation ha; 4485 ASSERT(args.length() == 1); 4486 CONVERT_CHECKED(String, subject, args[0]); 4487 subject->TryFlatten(); 4488 4489 // Fast case: short integer or some sorts of junk values. 4490 int len = subject->length(); 4491 if (subject->IsSeqAsciiString()) { 4492 if (len == 0) return Smi::FromInt(0); 4493 4494 char const* data = SeqAsciiString::cast(subject)->GetChars(); 4495 bool minus = (data[0] == '-'); 4496 int start_pos = (minus ? 1 : 0); 4497 4498 if (start_pos == len) { 4499 return Heap::nan_value(); 4500 } else if (data[start_pos] > '9') { 4501 // Fast check for a junk value. A valid string may start from a 4502 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or 4503 // the 'I' character ('Infinity'). All of that have codes not greater than 4504 // '9' except 'I'. 4505 if (data[start_pos] != 'I') { 4506 return Heap::nan_value(); 4507 } 4508 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 4509 // The maximal/minimal smi has 10 digits. If the string has less digits we 4510 // know it will fit into the smi-data type. 4511 int d = ParseDecimalInteger(data, start_pos, len); 4512 if (minus) { 4513 if (d == 0) return Heap::minus_zero_value(); 4514 d = -d; 4515 } 4516 return Smi::FromInt(d); 4517 } 4518 } 4519 4520 // Slower case. 4521 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); 4522} 4523 4524 4525static Object* Runtime_StringFromCharCodeArray(Arguments args) { 4526 NoHandleAllocation ha; 4527 ASSERT(args.length() == 1); 4528 4529 CONVERT_CHECKED(JSArray, codes, args[0]); 4530 int length = Smi::cast(codes->length())->value(); 4531 4532 // Check if the string can be ASCII. 4533 int i; 4534 for (i = 0; i < length; i++) { 4535 Object* element = codes->GetElement(i); 4536 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); 4537 if ((chr & 0xffff) > String::kMaxAsciiCharCode) 4538 break; 4539 } 4540 4541 Object* object = NULL; 4542 if (i == length) { // The string is ASCII. 4543 object = Heap::AllocateRawAsciiString(length); 4544 } else { // The string is not ASCII. 4545 object = Heap::AllocateRawTwoByteString(length); 4546 } 4547 4548 if (object->IsFailure()) return object; 4549 String* result = String::cast(object); 4550 for (int i = 0; i < length; i++) { 4551 Object* element = codes->GetElement(i); 4552 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); 4553 result->Set(i, chr & 0xffff); 4554 } 4555 return result; 4556} 4557 4558 4559// kNotEscaped is generated by the following: 4560// 4561// #!/bin/perl 4562// for (my $i = 0; $i < 256; $i++) { 4563// print "\n" if $i % 16 == 0; 4564// my $c = chr($i); 4565// my $escaped = 1; 4566// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#; 4567// print $escaped ? "0, " : "1, "; 4568// } 4569 4570 4571static bool IsNotEscaped(uint16_t character) { 4572 // Only for 8 bit characters, the rest are always escaped (in a different way) 4573 ASSERT(character < 256); 4574 static const char kNotEscaped[256] = { 4575 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4576 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4577 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 4578 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4579 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4580 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 4581 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4582 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 4583 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4584 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4585 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4586 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4587 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4588 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4590 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4591 }; 4592 return kNotEscaped[character] != 0; 4593} 4594 4595 4596static Object* Runtime_URIEscape(Arguments args) { 4597 const char hex_chars[] = "0123456789ABCDEF"; 4598 NoHandleAllocation ha; 4599 ASSERT(args.length() == 1); 4600 CONVERT_CHECKED(String, source, args[0]); 4601 4602 source->TryFlatten(); 4603 4604 int escaped_length = 0; 4605 int length = source->length(); 4606 { 4607 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); 4608 buffer->Reset(source); 4609 while (buffer->has_more()) { 4610 uint16_t character = buffer->GetNext(); 4611 if (character >= 256) { 4612 escaped_length += 6; 4613 } else if (IsNotEscaped(character)) { 4614 escaped_length++; 4615 } else { 4616 escaped_length += 3; 4617 } 4618 // We don't allow strings that are longer than a maximal length. 4619 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow. 4620 if (escaped_length > String::kMaxLength) { 4621 Top::context()->mark_out_of_memory(); 4622 return Failure::OutOfMemoryException(); 4623 } 4624 } 4625 } 4626 // No length change implies no change. Return original string if no change. 4627 if (escaped_length == length) { 4628 return source; 4629 } 4630 Object* o = Heap::AllocateRawAsciiString(escaped_length); 4631 if (o->IsFailure()) return o; 4632 String* destination = String::cast(o); 4633 int dest_position = 0; 4634 4635 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); 4636 buffer->Rewind(); 4637 while (buffer->has_more()) { 4638 uint16_t chr = buffer->GetNext(); 4639 if (chr >= 256) { 4640 destination->Set(dest_position, '%'); 4641 destination->Set(dest_position+1, 'u'); 4642 destination->Set(dest_position+2, hex_chars[chr >> 12]); 4643 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); 4644 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); 4645 destination->Set(dest_position+5, hex_chars[chr & 0xf]); 4646 dest_position += 6; 4647 } else if (IsNotEscaped(chr)) { 4648 destination->Set(dest_position, chr); 4649 dest_position++; 4650 } else { 4651 destination->Set(dest_position, '%'); 4652 destination->Set(dest_position+1, hex_chars[chr >> 4]); 4653 destination->Set(dest_position+2, hex_chars[chr & 0xf]); 4654 dest_position += 3; 4655 } 4656 } 4657 return destination; 4658} 4659 4660 4661static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { 4662 static const signed char kHexValue['g'] = { 4663 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4664 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4665 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4666 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 4667 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4668 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4669 -1, 10, 11, 12, 13, 14, 15 }; 4670 4671 if (character1 > 'f') return -1; 4672 int hi = kHexValue[character1]; 4673 if (hi == -1) return -1; 4674 if (character2 > 'f') return -1; 4675 int lo = kHexValue[character2]; 4676 if (lo == -1) return -1; 4677 return (hi << 4) + lo; 4678} 4679 4680 4681static inline int Unescape(String* source, 4682 int i, 4683 int length, 4684 int* step) { 4685 uint16_t character = source->Get(i); 4686 int32_t hi = 0; 4687 int32_t lo = 0; 4688 if (character == '%' && 4689 i <= length - 6 && 4690 source->Get(i + 1) == 'u' && 4691 (hi = TwoDigitHex(source->Get(i + 2), 4692 source->Get(i + 3))) != -1 && 4693 (lo = TwoDigitHex(source->Get(i + 4), 4694 source->Get(i + 5))) != -1) { 4695 *step = 6; 4696 return (hi << 8) + lo; 4697 } else if (character == '%' && 4698 i <= length - 3 && 4699 (lo = TwoDigitHex(source->Get(i + 1), 4700 source->Get(i + 2))) != -1) { 4701 *step = 3; 4702 return lo; 4703 } else { 4704 *step = 1; 4705 return character; 4706 } 4707} 4708 4709 4710static Object* Runtime_URIUnescape(Arguments args) { 4711 NoHandleAllocation ha; 4712 ASSERT(args.length() == 1); 4713 CONVERT_CHECKED(String, source, args[0]); 4714 4715 source->TryFlatten(); 4716 4717 bool ascii = true; 4718 int length = source->length(); 4719 4720 int unescaped_length = 0; 4721 for (int i = 0; i < length; unescaped_length++) { 4722 int step; 4723 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) { 4724 ascii = false; 4725 } 4726 i += step; 4727 } 4728 4729 // No length change implies no change. Return original string if no change. 4730 if (unescaped_length == length) 4731 return source; 4732 4733 Object* o = ascii ? 4734 Heap::AllocateRawAsciiString(unescaped_length) : 4735 Heap::AllocateRawTwoByteString(unescaped_length); 4736 if (o->IsFailure()) return o; 4737 String* destination = String::cast(o); 4738 4739 int dest_position = 0; 4740 for (int i = 0; i < length; dest_position++) { 4741 int step; 4742 destination->Set(dest_position, Unescape(source, i, length, &step)); 4743 i += step; 4744 } 4745 return destination; 4746} 4747 4748 4749static Object* Runtime_StringParseInt(Arguments args) { 4750 NoHandleAllocation ha; 4751 4752 CONVERT_CHECKED(String, s, args[0]); 4753 CONVERT_SMI_CHECKED(radix, args[1]); 4754 4755 s->TryFlatten(); 4756 4757 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); 4758 double value = StringToInt(s, radix); 4759 return Heap::NumberFromDouble(value); 4760 return Heap::nan_value(); 4761} 4762 4763 4764static Object* Runtime_StringParseFloat(Arguments args) { 4765 NoHandleAllocation ha; 4766 CONVERT_CHECKED(String, str, args[0]); 4767 4768 // ECMA-262 section 15.1.2.3, empty string is NaN 4769 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value()); 4770 4771 // Create a number object from the value. 4772 return Heap::NumberFromDouble(value); 4773} 4774 4775 4776static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; 4777static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; 4778 4779 4780template <class Converter> 4781static Object* ConvertCaseHelper(String* s, 4782 int length, 4783 int input_string_length, 4784 unibrow::Mapping<Converter, 128>* mapping) { 4785 // We try this twice, once with the assumption that the result is no longer 4786 // than the input and, if that assumption breaks, again with the exact 4787 // length. This may not be pretty, but it is nicer than what was here before 4788 // and I hereby claim my vaffel-is. 4789 // 4790 // Allocate the resulting string. 4791 // 4792 // NOTE: This assumes that the upper/lower case of an ascii 4793 // character is also ascii. This is currently the case, but it 4794 // might break in the future if we implement more context and locale 4795 // dependent upper/lower conversions. 4796 Object* o = s->IsAsciiRepresentation() 4797 ? Heap::AllocateRawAsciiString(length) 4798 : Heap::AllocateRawTwoByteString(length); 4799 if (o->IsFailure()) return o; 4800 String* result = String::cast(o); 4801 bool has_changed_character = false; 4802 4803 // Convert all characters to upper case, assuming that they will fit 4804 // in the buffer 4805 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); 4806 buffer->Reset(s); 4807 unibrow::uchar chars[Converter::kMaxWidth]; 4808 // We can assume that the string is not empty 4809 uc32 current = buffer->GetNext(); 4810 for (int i = 0; i < length;) { 4811 bool has_next = buffer->has_more(); 4812 uc32 next = has_next ? buffer->GetNext() : 0; 4813 int char_length = mapping->get(current, next, chars); 4814 if (char_length == 0) { 4815 // The case conversion of this character is the character itself. 4816 result->Set(i, current); 4817 i++; 4818 } else if (char_length == 1) { 4819 // Common case: converting the letter resulted in one character. 4820 ASSERT(static_cast<uc32>(chars[0]) != current); 4821 result->Set(i, chars[0]); 4822 has_changed_character = true; 4823 i++; 4824 } else if (length == input_string_length) { 4825 // We've assumed that the result would be as long as the 4826 // input but here is a character that converts to several 4827 // characters. No matter, we calculate the exact length 4828 // of the result and try the whole thing again. 4829 // 4830 // Note that this leaves room for optimization. We could just 4831 // memcpy what we already have to the result string. Also, 4832 // the result string is the last object allocated we could 4833 // "realloc" it and probably, in the vast majority of cases, 4834 // extend the existing string to be able to hold the full 4835 // result. 4836 int next_length = 0; 4837 if (has_next) { 4838 next_length = mapping->get(next, 0, chars); 4839 if (next_length == 0) next_length = 1; 4840 } 4841 int current_length = i + char_length + next_length; 4842 while (buffer->has_more()) { 4843 current = buffer->GetNext(); 4844 // NOTE: we use 0 as the next character here because, while 4845 // the next character may affect what a character converts to, 4846 // it does not in any case affect the length of what it convert 4847 // to. 4848 int char_length = mapping->get(current, 0, chars); 4849 if (char_length == 0) char_length = 1; 4850 current_length += char_length; 4851 if (current_length > Smi::kMaxValue) { 4852 Top::context()->mark_out_of_memory(); 4853 return Failure::OutOfMemoryException(); 4854 } 4855 } 4856 // Try again with the real length. 4857 return Smi::FromInt(current_length); 4858 } else { 4859 for (int j = 0; j < char_length; j++) { 4860 result->Set(i, chars[j]); 4861 i++; 4862 } 4863 has_changed_character = true; 4864 } 4865 current = next; 4866 } 4867 if (has_changed_character) { 4868 return result; 4869 } else { 4870 // If we didn't actually change anything in doing the conversion 4871 // we simple return the result and let the converted string 4872 // become garbage; there is no reason to keep two identical strings 4873 // alive. 4874 return s; 4875 } 4876} 4877 4878 4879static inline SeqAsciiString* TryGetSeqAsciiString(String* s) { 4880 if (!s->IsFlat() || !s->IsAsciiRepresentation()) return NULL; 4881 if (s->IsConsString()) { 4882 ASSERT(ConsString::cast(s)->second()->length() == 0); 4883 return SeqAsciiString::cast(ConsString::cast(s)->first()); 4884 } 4885 return SeqAsciiString::cast(s); 4886} 4887 4888 4889namespace { 4890 4891struct ToLowerTraits { 4892 typedef unibrow::ToLowercase UnibrowConverter; 4893 4894 static bool ConvertAscii(char* dst, char* src, int length) { 4895 bool changed = false; 4896 for (int i = 0; i < length; ++i) { 4897 char c = src[i]; 4898 if ('A' <= c && c <= 'Z') { 4899 c += ('a' - 'A'); 4900 changed = true; 4901 } 4902 dst[i] = c; 4903 } 4904 return changed; 4905 } 4906}; 4907 4908 4909struct ToUpperTraits { 4910 typedef unibrow::ToUppercase UnibrowConverter; 4911 4912 static bool ConvertAscii(char* dst, char* src, int length) { 4913 bool changed = false; 4914 for (int i = 0; i < length; ++i) { 4915 char c = src[i]; 4916 if ('a' <= c && c <= 'z') { 4917 c -= ('a' - 'A'); 4918 changed = true; 4919 } 4920 dst[i] = c; 4921 } 4922 return changed; 4923 } 4924}; 4925 4926} // namespace 4927 4928 4929template <typename ConvertTraits> 4930static Object* ConvertCase( 4931 Arguments args, 4932 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) { 4933 NoHandleAllocation ha; 4934 CONVERT_CHECKED(String, s, args[0]); 4935 s->TryFlatten(); 4936 4937 const int length = s->length(); 4938 // Assume that the string is not empty; we need this assumption later 4939 if (length == 0) return s; 4940 4941 // Simpler handling of ascii strings. 4942 // 4943 // NOTE: This assumes that the upper/lower case of an ascii 4944 // character is also ascii. This is currently the case, but it 4945 // might break in the future if we implement more context and locale 4946 // dependent upper/lower conversions. 4947 SeqAsciiString* seq_ascii = TryGetSeqAsciiString(s); 4948 if (seq_ascii != NULL) { 4949 Object* o = Heap::AllocateRawAsciiString(length); 4950 if (o->IsFailure()) return o; 4951 SeqAsciiString* result = SeqAsciiString::cast(o); 4952 bool has_changed_character = ConvertTraits::ConvertAscii( 4953 result->GetChars(), seq_ascii->GetChars(), length); 4954 return has_changed_character ? result : s; 4955 } 4956 4957 Object* answer = ConvertCaseHelper(s, length, length, mapping); 4958 if (answer->IsSmi()) { 4959 // Retry with correct length. 4960 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping); 4961 } 4962 return answer; // This may be a failure. 4963} 4964 4965 4966static Object* Runtime_StringToLowerCase(Arguments args) { 4967 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping); 4968} 4969 4970 4971static Object* Runtime_StringToUpperCase(Arguments args) { 4972 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping); 4973} 4974 4975 4976static inline bool IsTrimWhiteSpace(unibrow::uchar c) { 4977 return unibrow::WhiteSpace::Is(c) || c == 0x200b; 4978} 4979 4980 4981static Object* Runtime_StringTrim(Arguments args) { 4982 NoHandleAllocation ha; 4983 ASSERT(args.length() == 3); 4984 4985 CONVERT_CHECKED(String, s, args[0]); 4986 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]); 4987 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]); 4988 4989 s->TryFlatten(); 4990 int length = s->length(); 4991 4992 int left = 0; 4993 if (trimLeft) { 4994 while (left < length && IsTrimWhiteSpace(s->Get(left))) { 4995 left++; 4996 } 4997 } 4998 4999 int right = length; 5000 if (trimRight) { 5001 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { 5002 right--; 5003 } 5004 } 5005 return s->SubString(left, right); 5006} 5007 5008 5009template <typename schar, typename pchar> 5010void FindStringIndices(Vector<const schar> subject, 5011 Vector<const pchar> pattern, 5012 ZoneList<int>* indices, 5013 unsigned int limit) { 5014 ASSERT(limit > 0); 5015 // Collect indices of pattern in subject, and the end-of-string index. 5016 // Stop after finding at most limit values. 5017 StringSearchStrategy strategy = 5018 InitializeStringSearch(pattern, sizeof(schar) == 1); 5019 switch (strategy) { 5020 case SEARCH_FAIL: return; 5021 case SEARCH_SHORT: { 5022 int pattern_length = pattern.length(); 5023 int index = 0; 5024 while (limit > 0) { 5025 index = SimpleIndexOf(subject, pattern, index); 5026 if (index < 0) return; 5027 indices->Add(index); 5028 index += pattern_length; 5029 limit--; 5030 } 5031 return; 5032 } 5033 case SEARCH_LONG: { 5034 int pattern_length = pattern.length(); 5035 int index = 0; 5036 while (limit > 0) { 5037 index = ComplexIndexOf(subject, pattern, index); 5038 if (index < 0) return; 5039 indices->Add(index); 5040 index += pattern_length; 5041 limit--; 5042 } 5043 return; 5044 } 5045 default: 5046 UNREACHABLE(); 5047 return; 5048 } 5049} 5050 5051template <typename schar> 5052inline void FindCharIndices(Vector<const schar> subject, 5053 const schar pattern_char, 5054 ZoneList<int>* indices, 5055 unsigned int limit) { 5056 // Collect indices of pattern_char in subject, and the end-of-string index. 5057 // Stop after finding at most limit values. 5058 int index = 0; 5059 while (limit > 0) { 5060 index = SingleCharIndexOf(subject, pattern_char, index); 5061 if (index < 0) return; 5062 indices->Add(index); 5063 index++; 5064 limit--; 5065 } 5066} 5067 5068 5069static Object* Runtime_StringSplit(Arguments args) { 5070 ASSERT(args.length() == 3); 5071 HandleScope handle_scope; 5072 CONVERT_ARG_CHECKED(String, subject, 0); 5073 CONVERT_ARG_CHECKED(String, pattern, 1); 5074 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); 5075 5076 int subject_length = subject->length(); 5077 int pattern_length = pattern->length(); 5078 RUNTIME_ASSERT(pattern_length > 0); 5079 5080 // The limit can be very large (0xffffffffu), but since the pattern 5081 // isn't empty, we can never create more parts than ~half the length 5082 // of the subject. 5083 5084 if (!subject->IsFlat()) FlattenString(subject); 5085 5086 static const int kMaxInitialListCapacity = 16; 5087 5088 ZoneScope scope(DELETE_ON_EXIT); 5089 5090 // Find (up to limit) indices of separator and end-of-string in subject 5091 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); 5092 ZoneList<int> indices(initial_capacity); 5093 if (pattern_length == 1) { 5094 // Special case, go directly to fast single-character split. 5095 AssertNoAllocation nogc; 5096 uc16 pattern_char = pattern->Get(0); 5097 if (subject->IsTwoByteRepresentation()) { 5098 FindCharIndices(subject->ToUC16Vector(), pattern_char, 5099 &indices, 5100 limit); 5101 } else if (pattern_char <= String::kMaxAsciiCharCode) { 5102 FindCharIndices(subject->ToAsciiVector(), 5103 static_cast<char>(pattern_char), 5104 &indices, 5105 limit); 5106 } 5107 } else { 5108 if (!pattern->IsFlat()) FlattenString(pattern); 5109 AssertNoAllocation nogc; 5110 if (subject->IsAsciiRepresentation()) { 5111 Vector<const char> subject_vector = subject->ToAsciiVector(); 5112 if (pattern->IsAsciiRepresentation()) { 5113 FindStringIndices(subject_vector, 5114 pattern->ToAsciiVector(), 5115 &indices, 5116 limit); 5117 } else { 5118 FindStringIndices(subject_vector, 5119 pattern->ToUC16Vector(), 5120 &indices, 5121 limit); 5122 } 5123 } else { 5124 Vector<const uc16> subject_vector = subject->ToUC16Vector(); 5125 if (pattern->IsAsciiRepresentation()) { 5126 FindStringIndices(subject_vector, 5127 pattern->ToAsciiVector(), 5128 &indices, 5129 limit); 5130 } else { 5131 FindStringIndices(subject_vector, 5132 pattern->ToUC16Vector(), 5133 &indices, 5134 limit); 5135 } 5136 } 5137 } 5138 if (static_cast<uint32_t>(indices.length()) < limit) { 5139 indices.Add(subject_length); 5140 } 5141 // The list indices now contains the end of each part to create. 5142 5143 5144 // Create JSArray of substrings separated by separator. 5145 int part_count = indices.length(); 5146 5147 Handle<JSArray> result = Factory::NewJSArray(part_count); 5148 result->set_length(Smi::FromInt(part_count)); 5149 5150 ASSERT(result->HasFastElements()); 5151 5152 if (part_count == 1 && indices.at(0) == subject_length) { 5153 FixedArray::cast(result->elements())->set(0, *subject); 5154 return *result; 5155 } 5156 5157 Handle<FixedArray> elements(FixedArray::cast(result->elements())); 5158 int part_start = 0; 5159 for (int i = 0; i < part_count; i++) { 5160 HandleScope local_loop_handle; 5161 int part_end = indices.at(i); 5162 Handle<String> substring = 5163 Factory::NewSubString(subject, part_start, part_end); 5164 elements->set(i, *substring); 5165 part_start = part_end + pattern_length; 5166 } 5167 5168 return *result; 5169} 5170 5171 5172// Copies ascii characters to the given fixed array looking up 5173// one-char strings in the cache. Gives up on the first char that is 5174// not in the cache and fills the remainder with smi zeros. Returns 5175// the length of the successfully copied prefix. 5176static int CopyCachedAsciiCharsToArray(const char* chars, 5177 FixedArray* elements, 5178 int length) { 5179 AssertNoAllocation nogc; 5180 FixedArray* ascii_cache = Heap::single_character_string_cache(); 5181 Object* undefined = Heap::undefined_value(); 5182 int i; 5183 for (i = 0; i < length; ++i) { 5184 Object* value = ascii_cache->get(chars[i]); 5185 if (value == undefined) break; 5186 ASSERT(!Heap::InNewSpace(value)); 5187 elements->set(i, value, SKIP_WRITE_BARRIER); 5188 } 5189 if (i < length) { 5190 ASSERT(Smi::FromInt(0) == 0); 5191 memset(elements->data_start() + i, 0, kPointerSize * (length - i)); 5192 } 5193#ifdef DEBUG 5194 for (int j = 0; j < length; ++j) { 5195 Object* element = elements->get(j); 5196 ASSERT(element == Smi::FromInt(0) || 5197 (element->IsString() && String::cast(element)->LooksValid())); 5198 } 5199#endif 5200 return i; 5201} 5202 5203 5204// Converts a String to JSArray. 5205// For example, "foo" => ["f", "o", "o"]. 5206static Object* Runtime_StringToArray(Arguments args) { 5207 HandleScope scope; 5208 ASSERT(args.length() == 1); 5209 CONVERT_ARG_CHECKED(String, s, 0); 5210 5211 s->TryFlatten(); 5212 const int length = s->length(); 5213 5214 Handle<FixedArray> elements; 5215 if (s->IsFlat() && s->IsAsciiRepresentation()) { 5216 Object* obj = Heap::AllocateUninitializedFixedArray(length); 5217 if (obj->IsFailure()) return obj; 5218 elements = Handle<FixedArray>(FixedArray::cast(obj)); 5219 5220 Vector<const char> chars = s->ToAsciiVector(); 5221 // Note, this will initialize all elements (not only the prefix) 5222 // to prevent GC from seeing partially initialized array. 5223 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(), 5224 *elements, 5225 length); 5226 5227 for (int i = num_copied_from_cache; i < length; ++i) { 5228 elements->set(i, *LookupSingleCharacterStringFromCode(chars[i])); 5229 } 5230 } else { 5231 elements = Factory::NewFixedArray(length); 5232 for (int i = 0; i < length; ++i) { 5233 elements->set(i, *LookupSingleCharacterStringFromCode(s->Get(i))); 5234 } 5235 } 5236 5237#ifdef DEBUG 5238 for (int i = 0; i < length; ++i) { 5239 ASSERT(String::cast(elements->get(i))->length() == 1); 5240 } 5241#endif 5242 5243 return *Factory::NewJSArrayWithElements(elements); 5244} 5245 5246 5247bool Runtime::IsUpperCaseChar(uint16_t ch) { 5248 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; 5249 int char_length = to_upper_mapping.get(ch, 0, chars); 5250 return char_length == 0; 5251} 5252 5253 5254static Object* Runtime_NumberToString(Arguments args) { 5255 NoHandleAllocation ha; 5256 ASSERT(args.length() == 1); 5257 5258 Object* number = args[0]; 5259 RUNTIME_ASSERT(number->IsNumber()); 5260 5261 return Heap::NumberToString(number); 5262} 5263 5264 5265static Object* Runtime_NumberToStringSkipCache(Arguments args) { 5266 NoHandleAllocation ha; 5267 ASSERT(args.length() == 1); 5268 5269 Object* number = args[0]; 5270 RUNTIME_ASSERT(number->IsNumber()); 5271 5272 return Heap::NumberToString(number, false); 5273} 5274 5275 5276static Object* Runtime_NumberToInteger(Arguments args) { 5277 NoHandleAllocation ha; 5278 ASSERT(args.length() == 1); 5279 5280 CONVERT_DOUBLE_CHECKED(number, args[0]); 5281 5282 // We do not include 0 so that we don't have to treat +0 / -0 cases. 5283 if (number > 0 && number <= Smi::kMaxValue) { 5284 return Smi::FromInt(static_cast<int>(number)); 5285 } 5286 return Heap::NumberFromDouble(DoubleToInteger(number)); 5287} 5288 5289 5290static Object* Runtime_NumberToJSUint32(Arguments args) { 5291 NoHandleAllocation ha; 5292 ASSERT(args.length() == 1); 5293 5294 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); 5295 return Heap::NumberFromUint32(number); 5296} 5297 5298 5299static Object* Runtime_NumberToJSInt32(Arguments args) { 5300 NoHandleAllocation ha; 5301 ASSERT(args.length() == 1); 5302 5303 CONVERT_DOUBLE_CHECKED(number, args[0]); 5304 5305 // We do not include 0 so that we don't have to treat +0 / -0 cases. 5306 if (number > 0 && number <= Smi::kMaxValue) { 5307 return Smi::FromInt(static_cast<int>(number)); 5308 } 5309 return Heap::NumberFromInt32(DoubleToInt32(number)); 5310} 5311 5312 5313// Converts a Number to a Smi, if possible. Returns NaN if the number is not 5314// a small integer. 5315static Object* Runtime_NumberToSmi(Arguments args) { 5316 NoHandleAllocation ha; 5317 ASSERT(args.length() == 1); 5318 5319 Object* obj = args[0]; 5320 if (obj->IsSmi()) { 5321 return obj; 5322 } 5323 if (obj->IsHeapNumber()) { 5324 double value = HeapNumber::cast(obj)->value(); 5325 int int_value = FastD2I(value); 5326 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { 5327 return Smi::FromInt(int_value); 5328 } 5329 } 5330 return Heap::nan_value(); 5331} 5332 5333 5334static Object* Runtime_NumberAdd(Arguments args) { 5335 NoHandleAllocation ha; 5336 ASSERT(args.length() == 2); 5337 5338 CONVERT_DOUBLE_CHECKED(x, args[0]); 5339 CONVERT_DOUBLE_CHECKED(y, args[1]); 5340 return Heap::AllocateHeapNumber(x + y); 5341} 5342 5343 5344static Object* Runtime_NumberSub(Arguments args) { 5345 NoHandleAllocation ha; 5346 ASSERT(args.length() == 2); 5347 5348 CONVERT_DOUBLE_CHECKED(x, args[0]); 5349 CONVERT_DOUBLE_CHECKED(y, args[1]); 5350 return Heap::AllocateHeapNumber(x - y); 5351} 5352 5353 5354static Object* Runtime_NumberMul(Arguments args) { 5355 NoHandleAllocation ha; 5356 ASSERT(args.length() == 2); 5357 5358 CONVERT_DOUBLE_CHECKED(x, args[0]); 5359 CONVERT_DOUBLE_CHECKED(y, args[1]); 5360 return Heap::AllocateHeapNumber(x * y); 5361} 5362 5363 5364static Object* Runtime_NumberUnaryMinus(Arguments args) { 5365 NoHandleAllocation ha; 5366 ASSERT(args.length() == 1); 5367 5368 CONVERT_DOUBLE_CHECKED(x, args[0]); 5369 return Heap::AllocateHeapNumber(-x); 5370} 5371 5372 5373static Object* Runtime_NumberDiv(Arguments args) { 5374 NoHandleAllocation ha; 5375 ASSERT(args.length() == 2); 5376 5377 CONVERT_DOUBLE_CHECKED(x, args[0]); 5378 CONVERT_DOUBLE_CHECKED(y, args[1]); 5379 return Heap::NumberFromDouble(x / y); 5380} 5381 5382 5383static Object* Runtime_NumberMod(Arguments args) { 5384 NoHandleAllocation ha; 5385 ASSERT(args.length() == 2); 5386 5387 CONVERT_DOUBLE_CHECKED(x, args[0]); 5388 CONVERT_DOUBLE_CHECKED(y, args[1]); 5389 5390 x = modulo(x, y); 5391 // NumberFromDouble may return a Smi instead of a Number object 5392 return Heap::NumberFromDouble(x); 5393} 5394 5395 5396static Object* Runtime_StringAdd(Arguments args) { 5397 NoHandleAllocation ha; 5398 ASSERT(args.length() == 2); 5399 CONVERT_CHECKED(String, str1, args[0]); 5400 CONVERT_CHECKED(String, str2, args[1]); 5401 Counters::string_add_runtime.Increment(); 5402 return Heap::AllocateConsString(str1, str2); 5403} 5404 5405 5406template <typename sinkchar> 5407static inline void StringBuilderConcatHelper(String* special, 5408 sinkchar* sink, 5409 FixedArray* fixed_array, 5410 int array_length) { 5411 int position = 0; 5412 for (int i = 0; i < array_length; i++) { 5413 Object* element = fixed_array->get(i); 5414 if (element->IsSmi()) { 5415 // Smi encoding of position and length. 5416 int encoded_slice = Smi::cast(element)->value(); 5417 int pos; 5418 int len; 5419 if (encoded_slice > 0) { 5420 // Position and length encoded in one smi. 5421 pos = StringBuilderSubstringPosition::decode(encoded_slice); 5422 len = StringBuilderSubstringLength::decode(encoded_slice); 5423 } else { 5424 // Position and length encoded in two smis. 5425 Object* obj = fixed_array->get(++i); 5426 ASSERT(obj->IsSmi()); 5427 pos = Smi::cast(obj)->value(); 5428 len = -encoded_slice; 5429 } 5430 String::WriteToFlat(special, 5431 sink + position, 5432 pos, 5433 pos + len); 5434 position += len; 5435 } else { 5436 String* string = String::cast(element); 5437 int element_length = string->length(); 5438 String::WriteToFlat(string, sink + position, 0, element_length); 5439 position += element_length; 5440 } 5441 } 5442} 5443 5444 5445static Object* Runtime_StringBuilderConcat(Arguments args) { 5446 NoHandleAllocation ha; 5447 ASSERT(args.length() == 3); 5448 CONVERT_CHECKED(JSArray, array, args[0]); 5449 if (!args[1]->IsSmi()) { 5450 Top::context()->mark_out_of_memory(); 5451 return Failure::OutOfMemoryException(); 5452 } 5453 int array_length = Smi::cast(args[1])->value(); 5454 CONVERT_CHECKED(String, special, args[2]); 5455 5456 // This assumption is used by the slice encoding in one or two smis. 5457 ASSERT(Smi::kMaxValue >= String::kMaxLength); 5458 5459 int special_length = special->length(); 5460 if (!array->HasFastElements()) { 5461 return Top::Throw(Heap::illegal_argument_symbol()); 5462 } 5463 FixedArray* fixed_array = FixedArray::cast(array->elements()); 5464 if (fixed_array->length() < array_length) { 5465 array_length = fixed_array->length(); 5466 } 5467 5468 if (array_length == 0) { 5469 return Heap::empty_string(); 5470 } else if (array_length == 1) { 5471 Object* first = fixed_array->get(0); 5472 if (first->IsString()) return first; 5473 } 5474 5475 bool ascii = special->IsAsciiRepresentation(); 5476 int position = 0; 5477 for (int i = 0; i < array_length; i++) { 5478 int increment = 0; 5479 Object* elt = fixed_array->get(i); 5480 if (elt->IsSmi()) { 5481 // Smi encoding of position and length. 5482 int smi_value = Smi::cast(elt)->value(); 5483 int pos; 5484 int len; 5485 if (smi_value > 0) { 5486 // Position and length encoded in one smi. 5487 pos = StringBuilderSubstringPosition::decode(smi_value); 5488 len = StringBuilderSubstringLength::decode(smi_value); 5489 } else { 5490 // Position and length encoded in two smis. 5491 len = -smi_value; 5492 // Get the position and check that it is a positive smi. 5493 i++; 5494 if (i >= array_length) { 5495 return Top::Throw(Heap::illegal_argument_symbol()); 5496 } 5497 Object* next_smi = fixed_array->get(i); 5498 if (!next_smi->IsSmi()) { 5499 return Top::Throw(Heap::illegal_argument_symbol()); 5500 } 5501 pos = Smi::cast(next_smi)->value(); 5502 if (pos < 0) { 5503 return Top::Throw(Heap::illegal_argument_symbol()); 5504 } 5505 } 5506 ASSERT(pos >= 0); 5507 ASSERT(len >= 0); 5508 if (pos > special_length || len > special_length - pos) { 5509 return Top::Throw(Heap::illegal_argument_symbol()); 5510 } 5511 increment = len; 5512 } else if (elt->IsString()) { 5513 String* element = String::cast(elt); 5514 int element_length = element->length(); 5515 increment = element_length; 5516 if (ascii && !element->IsAsciiRepresentation()) { 5517 ascii = false; 5518 } 5519 } else { 5520 return Top::Throw(Heap::illegal_argument_symbol()); 5521 } 5522 if (increment > String::kMaxLength - position) { 5523 Top::context()->mark_out_of_memory(); 5524 return Failure::OutOfMemoryException(); 5525 } 5526 position += increment; 5527 } 5528 5529 int length = position; 5530 Object* object; 5531 5532 if (ascii) { 5533 object = Heap::AllocateRawAsciiString(length); 5534 if (object->IsFailure()) return object; 5535 SeqAsciiString* answer = SeqAsciiString::cast(object); 5536 StringBuilderConcatHelper(special, 5537 answer->GetChars(), 5538 fixed_array, 5539 array_length); 5540 return answer; 5541 } else { 5542 object = Heap::AllocateRawTwoByteString(length); 5543 if (object->IsFailure()) return object; 5544 SeqTwoByteString* answer = SeqTwoByteString::cast(object); 5545 StringBuilderConcatHelper(special, 5546 answer->GetChars(), 5547 fixed_array, 5548 array_length); 5549 return answer; 5550 } 5551} 5552 5553 5554static Object* Runtime_NumberOr(Arguments args) { 5555 NoHandleAllocation ha; 5556 ASSERT(args.length() == 2); 5557 5558 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 5559 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 5560 return Heap::NumberFromInt32(x | y); 5561} 5562 5563 5564static Object* Runtime_NumberAnd(Arguments args) { 5565 NoHandleAllocation ha; 5566 ASSERT(args.length() == 2); 5567 5568 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 5569 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 5570 return Heap::NumberFromInt32(x & y); 5571} 5572 5573 5574static Object* Runtime_NumberXor(Arguments args) { 5575 NoHandleAllocation ha; 5576 ASSERT(args.length() == 2); 5577 5578 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 5579 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 5580 return Heap::NumberFromInt32(x ^ y); 5581} 5582 5583 5584static Object* Runtime_NumberNot(Arguments args) { 5585 NoHandleAllocation ha; 5586 ASSERT(args.length() == 1); 5587 5588 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 5589 return Heap::NumberFromInt32(~x); 5590} 5591 5592 5593static Object* Runtime_NumberShl(Arguments args) { 5594 NoHandleAllocation ha; 5595 ASSERT(args.length() == 2); 5596 5597 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 5598 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 5599 return Heap::NumberFromInt32(x << (y & 0x1f)); 5600} 5601 5602 5603static Object* Runtime_NumberShr(Arguments args) { 5604 NoHandleAllocation ha; 5605 ASSERT(args.length() == 2); 5606 5607 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); 5608 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 5609 return Heap::NumberFromUint32(x >> (y & 0x1f)); 5610} 5611 5612 5613static Object* Runtime_NumberSar(Arguments args) { 5614 NoHandleAllocation ha; 5615 ASSERT(args.length() == 2); 5616 5617 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 5618 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 5619 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f)); 5620} 5621 5622 5623static Object* Runtime_NumberEquals(Arguments args) { 5624 NoHandleAllocation ha; 5625 ASSERT(args.length() == 2); 5626 5627 CONVERT_DOUBLE_CHECKED(x, args[0]); 5628 CONVERT_DOUBLE_CHECKED(y, args[1]); 5629 if (isnan(x)) return Smi::FromInt(NOT_EQUAL); 5630 if (isnan(y)) return Smi::FromInt(NOT_EQUAL); 5631 if (x == y) return Smi::FromInt(EQUAL); 5632 Object* result; 5633 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { 5634 result = Smi::FromInt(EQUAL); 5635 } else { 5636 result = Smi::FromInt(NOT_EQUAL); 5637 } 5638 return result; 5639} 5640 5641 5642static Object* Runtime_StringEquals(Arguments args) { 5643 NoHandleAllocation ha; 5644 ASSERT(args.length() == 2); 5645 5646 CONVERT_CHECKED(String, x, args[0]); 5647 CONVERT_CHECKED(String, y, args[1]); 5648 5649 bool not_equal = !x->Equals(y); 5650 // This is slightly convoluted because the value that signifies 5651 // equality is 0 and inequality is 1 so we have to negate the result 5652 // from String::Equals. 5653 ASSERT(not_equal == 0 || not_equal == 1); 5654 STATIC_CHECK(EQUAL == 0); 5655 STATIC_CHECK(NOT_EQUAL == 1); 5656 return Smi::FromInt(not_equal); 5657} 5658 5659 5660static Object* Runtime_NumberCompare(Arguments args) { 5661 NoHandleAllocation ha; 5662 ASSERT(args.length() == 3); 5663 5664 CONVERT_DOUBLE_CHECKED(x, args[0]); 5665 CONVERT_DOUBLE_CHECKED(y, args[1]); 5666 if (isnan(x) || isnan(y)) return args[2]; 5667 if (x == y) return Smi::FromInt(EQUAL); 5668 if (isless(x, y)) return Smi::FromInt(LESS); 5669 return Smi::FromInt(GREATER); 5670} 5671 5672 5673// Compare two Smis as if they were converted to strings and then 5674// compared lexicographically. 5675static Object* Runtime_SmiLexicographicCompare(Arguments args) { 5676 NoHandleAllocation ha; 5677 ASSERT(args.length() == 2); 5678 5679 // Arrays for the individual characters of the two Smis. Smis are 5680 // 31 bit integers and 10 decimal digits are therefore enough. 5681 static int x_elms[10]; 5682 static int y_elms[10]; 5683 5684 // Extract the integer values from the Smis. 5685 CONVERT_CHECKED(Smi, x, args[0]); 5686 CONVERT_CHECKED(Smi, y, args[1]); 5687 int x_value = x->value(); 5688 int y_value = y->value(); 5689 5690 // If the integers are equal so are the string representations. 5691 if (x_value == y_value) return Smi::FromInt(EQUAL); 5692 5693 // If one of the integers are zero the normal integer order is the 5694 // same as the lexicographic order of the string representations. 5695 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value); 5696 5697 // If only one of the integers is negative the negative number is 5698 // smallest because the char code of '-' is less than the char code 5699 // of any digit. Otherwise, we make both values positive. 5700 if (x_value < 0 || y_value < 0) { 5701 if (y_value >= 0) return Smi::FromInt(LESS); 5702 if (x_value >= 0) return Smi::FromInt(GREATER); 5703 x_value = -x_value; 5704 y_value = -y_value; 5705 } 5706 5707 // Convert the integers to arrays of their decimal digits. 5708 int x_index = 0; 5709 int y_index = 0; 5710 while (x_value > 0) { 5711 x_elms[x_index++] = x_value % 10; 5712 x_value /= 10; 5713 } 5714 while (y_value > 0) { 5715 y_elms[y_index++] = y_value % 10; 5716 y_value /= 10; 5717 } 5718 5719 // Loop through the arrays of decimal digits finding the first place 5720 // where they differ. 5721 while (--x_index >= 0 && --y_index >= 0) { 5722 int diff = x_elms[x_index] - y_elms[y_index]; 5723 if (diff != 0) return Smi::FromInt(diff); 5724 } 5725 5726 // If one array is a suffix of the other array, the longest array is 5727 // the representation of the largest of the Smis in the 5728 // lexicographic ordering. 5729 return Smi::FromInt(x_index - y_index); 5730} 5731 5732 5733static Object* StringInputBufferCompare(String* x, String* y) { 5734 static StringInputBuffer bufx; 5735 static StringInputBuffer bufy; 5736 bufx.Reset(x); 5737 bufy.Reset(y); 5738 while (bufx.has_more() && bufy.has_more()) { 5739 int d = bufx.GetNext() - bufy.GetNext(); 5740 if (d < 0) return Smi::FromInt(LESS); 5741 else if (d > 0) return Smi::FromInt(GREATER); 5742 } 5743 5744 // x is (non-trivial) prefix of y: 5745 if (bufy.has_more()) return Smi::FromInt(LESS); 5746 // y is prefix of x: 5747 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL); 5748} 5749 5750 5751static Object* FlatStringCompare(String* x, String* y) { 5752 ASSERT(x->IsFlat()); 5753 ASSERT(y->IsFlat()); 5754 Object* equal_prefix_result = Smi::FromInt(EQUAL); 5755 int prefix_length = x->length(); 5756 if (y->length() < prefix_length) { 5757 prefix_length = y->length(); 5758 equal_prefix_result = Smi::FromInt(GREATER); 5759 } else if (y->length() > prefix_length) { 5760 equal_prefix_result = Smi::FromInt(LESS); 5761 } 5762 int r; 5763 if (x->IsAsciiRepresentation()) { 5764 Vector<const char> x_chars = x->ToAsciiVector(); 5765 if (y->IsAsciiRepresentation()) { 5766 Vector<const char> y_chars = y->ToAsciiVector(); 5767 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 5768 } else { 5769 Vector<const uc16> y_chars = y->ToUC16Vector(); 5770 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 5771 } 5772 } else { 5773 Vector<const uc16> x_chars = x->ToUC16Vector(); 5774 if (y->IsAsciiRepresentation()) { 5775 Vector<const char> y_chars = y->ToAsciiVector(); 5776 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 5777 } else { 5778 Vector<const uc16> y_chars = y->ToUC16Vector(); 5779 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 5780 } 5781 } 5782 Object* result; 5783 if (r == 0) { 5784 result = equal_prefix_result; 5785 } else { 5786 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); 5787 } 5788 ASSERT(result == StringInputBufferCompare(x, y)); 5789 return result; 5790} 5791 5792 5793static Object* Runtime_StringCompare(Arguments args) { 5794 NoHandleAllocation ha; 5795 ASSERT(args.length() == 2); 5796 5797 CONVERT_CHECKED(String, x, args[0]); 5798 CONVERT_CHECKED(String, y, args[1]); 5799 5800 Counters::string_compare_runtime.Increment(); 5801 5802 // A few fast case tests before we flatten. 5803 if (x == y) return Smi::FromInt(EQUAL); 5804 if (y->length() == 0) { 5805 if (x->length() == 0) return Smi::FromInt(EQUAL); 5806 return Smi::FromInt(GREATER); 5807 } else if (x->length() == 0) { 5808 return Smi::FromInt(LESS); 5809 } 5810 5811 int d = x->Get(0) - y->Get(0); 5812 if (d < 0) return Smi::FromInt(LESS); 5813 else if (d > 0) return Smi::FromInt(GREATER); 5814 5815 Object* obj = Heap::PrepareForCompare(x); 5816 if (obj->IsFailure()) return obj; 5817 obj = Heap::PrepareForCompare(y); 5818 if (obj->IsFailure()) return obj; 5819 5820 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) 5821 : StringInputBufferCompare(x, y); 5822} 5823 5824 5825static Object* Runtime_Math_acos(Arguments args) { 5826 NoHandleAllocation ha; 5827 ASSERT(args.length() == 1); 5828 Counters::math_acos.Increment(); 5829 5830 CONVERT_DOUBLE_CHECKED(x, args[0]); 5831 return TranscendentalCache::Get(TranscendentalCache::ACOS, x); 5832} 5833 5834 5835static Object* Runtime_Math_asin(Arguments args) { 5836 NoHandleAllocation ha; 5837 ASSERT(args.length() == 1); 5838 Counters::math_asin.Increment(); 5839 5840 CONVERT_DOUBLE_CHECKED(x, args[0]); 5841 return TranscendentalCache::Get(TranscendentalCache::ASIN, x); 5842} 5843 5844 5845static Object* Runtime_Math_atan(Arguments args) { 5846 NoHandleAllocation ha; 5847 ASSERT(args.length() == 1); 5848 Counters::math_atan.Increment(); 5849 5850 CONVERT_DOUBLE_CHECKED(x, args[0]); 5851 return TranscendentalCache::Get(TranscendentalCache::ATAN, x); 5852} 5853 5854 5855static Object* Runtime_Math_atan2(Arguments args) { 5856 NoHandleAllocation ha; 5857 ASSERT(args.length() == 2); 5858 Counters::math_atan2.Increment(); 5859 5860 CONVERT_DOUBLE_CHECKED(x, args[0]); 5861 CONVERT_DOUBLE_CHECKED(y, args[1]); 5862 double result; 5863 if (isinf(x) && isinf(y)) { 5864 // Make sure that the result in case of two infinite arguments 5865 // is a multiple of Pi / 4. The sign of the result is determined 5866 // by the first argument (x) and the sign of the second argument 5867 // determines the multiplier: one or three. 5868 static double kPiDividedBy4 = 0.78539816339744830962; 5869 int multiplier = (x < 0) ? -1 : 1; 5870 if (y < 0) multiplier *= 3; 5871 result = multiplier * kPiDividedBy4; 5872 } else { 5873 result = atan2(x, y); 5874 } 5875 return Heap::AllocateHeapNumber(result); 5876} 5877 5878 5879static Object* Runtime_Math_ceil(Arguments args) { 5880 NoHandleAllocation ha; 5881 ASSERT(args.length() == 1); 5882 Counters::math_ceil.Increment(); 5883 5884 CONVERT_DOUBLE_CHECKED(x, args[0]); 5885 return Heap::NumberFromDouble(ceiling(x)); 5886} 5887 5888 5889static Object* Runtime_Math_cos(Arguments args) { 5890 NoHandleAllocation ha; 5891 ASSERT(args.length() == 1); 5892 Counters::math_cos.Increment(); 5893 5894 CONVERT_DOUBLE_CHECKED(x, args[0]); 5895 return TranscendentalCache::Get(TranscendentalCache::COS, x); 5896} 5897 5898 5899static Object* Runtime_Math_exp(Arguments args) { 5900 NoHandleAllocation ha; 5901 ASSERT(args.length() == 1); 5902 Counters::math_exp.Increment(); 5903 5904 CONVERT_DOUBLE_CHECKED(x, args[0]); 5905 return TranscendentalCache::Get(TranscendentalCache::EXP, x); 5906} 5907 5908 5909static Object* Runtime_Math_floor(Arguments args) { 5910 NoHandleAllocation ha; 5911 ASSERT(args.length() == 1); 5912 Counters::math_floor.Increment(); 5913 5914 CONVERT_DOUBLE_CHECKED(x, args[0]); 5915 return Heap::NumberFromDouble(floor(x)); 5916} 5917 5918 5919static Object* Runtime_Math_log(Arguments args) { 5920 NoHandleAllocation ha; 5921 ASSERT(args.length() == 1); 5922 Counters::math_log.Increment(); 5923 5924 CONVERT_DOUBLE_CHECKED(x, args[0]); 5925 return TranscendentalCache::Get(TranscendentalCache::LOG, x); 5926} 5927 5928 5929// Helper function to compute x^y, where y is known to be an 5930// integer. Uses binary decomposition to limit the number of 5931// multiplications; see the discussion in "Hacker's Delight" by Henry 5932// S. Warren, Jr., figure 11-6, page 213. 5933static double powi(double x, int y) { 5934 ASSERT(y != kMinInt); 5935 unsigned n = (y < 0) ? -y : y; 5936 double m = x; 5937 double p = 1; 5938 while (true) { 5939 if ((n & 1) != 0) p *= m; 5940 n >>= 1; 5941 if (n == 0) { 5942 if (y < 0) { 5943 // Unfortunately, we have to be careful when p has reached 5944 // infinity in the computation, because sometimes the higher 5945 // internal precision in the pow() implementation would have 5946 // given us a finite p. This happens very rarely. 5947 double result = 1.0 / p; 5948 return (result == 0 && isinf(p)) 5949 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int). 5950 : result; 5951 } else { 5952 return p; 5953 } 5954 } 5955 m *= m; 5956 } 5957} 5958 5959 5960static Object* Runtime_Math_pow(Arguments args) { 5961 NoHandleAllocation ha; 5962 ASSERT(args.length() == 2); 5963 Counters::math_pow.Increment(); 5964 5965 CONVERT_DOUBLE_CHECKED(x, args[0]); 5966 5967 // If the second argument is a smi, it is much faster to call the 5968 // custom powi() function than the generic pow(). 5969 if (args[1]->IsSmi()) { 5970 int y = Smi::cast(args[1])->value(); 5971 return Heap::AllocateHeapNumber(powi(x, y)); 5972 } 5973 5974 CONVERT_DOUBLE_CHECKED(y, args[1]); 5975 5976 if (!isinf(x)) { 5977 if (y == 0.5) { 5978 // It's not uncommon to use Math.pow(x, 0.5) to compute the 5979 // square root of a number. To speed up such computations, we 5980 // explictly check for this case and use the sqrt() function 5981 // which is faster than pow(). 5982 return Heap::AllocateHeapNumber(sqrt(x)); 5983 } else if (y == -0.5) { 5984 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5). 5985 return Heap::AllocateHeapNumber(1.0 / sqrt(x)); 5986 } 5987 } 5988 5989 if (y == 0) { 5990 return Smi::FromInt(1); 5991 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { 5992 return Heap::nan_value(); 5993 } else { 5994 return Heap::AllocateHeapNumber(pow(x, y)); 5995 } 5996} 5997 5998// Fast version of Math.pow if we know that y is not an integer and 5999// y is not -0.5 or 0.5. Used as slowcase from codegen. 6000static Object* Runtime_Math_pow_cfunction(Arguments args) { 6001 NoHandleAllocation ha; 6002 ASSERT(args.length() == 2); 6003 CONVERT_DOUBLE_CHECKED(x, args[0]); 6004 CONVERT_DOUBLE_CHECKED(y, args[1]); 6005 if (y == 0) { 6006 return Smi::FromInt(1); 6007 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { 6008 return Heap::nan_value(); 6009 } else { 6010 return Heap::AllocateHeapNumber(pow(x, y)); 6011 } 6012} 6013 6014 6015static Object* Runtime_RoundNumber(Arguments args) { 6016 NoHandleAllocation ha; 6017 ASSERT(args.length() == 1); 6018 Counters::math_round.Increment(); 6019 6020 if (!args[0]->IsHeapNumber()) { 6021 // Must be smi. Return the argument unchanged for all the other types 6022 // to make fuzz-natives test happy. 6023 return args[0]; 6024 } 6025 6026 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]); 6027 6028 double value = number->value(); 6029 int exponent = number->get_exponent(); 6030 int sign = number->get_sign(); 6031 6032 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and 6033 // should be rounded to 2^30, which is not smi. 6034 if (!sign && exponent <= kSmiValueSize - 3) { 6035 return Smi::FromInt(static_cast<int>(value + 0.5)); 6036 } 6037 6038 // If the magnitude is big enough, there's no place for fraction part. If we 6039 // try to add 0.5 to this number, 1.0 will be added instead. 6040 if (exponent >= 52) { 6041 return number; 6042 } 6043 6044 if (sign && value >= -0.5) return Heap::minus_zero_value(); 6045 6046 // Do not call NumberFromDouble() to avoid extra checks. 6047 return Heap::AllocateHeapNumber(floor(value + 0.5)); 6048} 6049 6050 6051static Object* Runtime_Math_sin(Arguments args) { 6052 NoHandleAllocation ha; 6053 ASSERT(args.length() == 1); 6054 Counters::math_sin.Increment(); 6055 6056 CONVERT_DOUBLE_CHECKED(x, args[0]); 6057 return TranscendentalCache::Get(TranscendentalCache::SIN, x); 6058} 6059 6060 6061static Object* Runtime_Math_sqrt(Arguments args) { 6062 NoHandleAllocation ha; 6063 ASSERT(args.length() == 1); 6064 Counters::math_sqrt.Increment(); 6065 6066 CONVERT_DOUBLE_CHECKED(x, args[0]); 6067 return Heap::AllocateHeapNumber(sqrt(x)); 6068} 6069 6070 6071static Object* Runtime_Math_tan(Arguments args) { 6072 NoHandleAllocation ha; 6073 ASSERT(args.length() == 1); 6074 Counters::math_tan.Increment(); 6075 6076 CONVERT_DOUBLE_CHECKED(x, args[0]); 6077 return TranscendentalCache::Get(TranscendentalCache::TAN, x); 6078} 6079 6080 6081static int MakeDay(int year, int month, int day) { 6082 static const int day_from_month[] = {0, 31, 59, 90, 120, 151, 6083 181, 212, 243, 273, 304, 334}; 6084 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152, 6085 182, 213, 244, 274, 305, 335}; 6086 6087 year += month / 12; 6088 month %= 12; 6089 if (month < 0) { 6090 year--; 6091 month += 12; 6092 } 6093 6094 ASSERT(month >= 0); 6095 ASSERT(month < 12); 6096 6097 // year_delta is an arbitrary number such that: 6098 // a) year_delta = -1 (mod 400) 6099 // b) year + year_delta > 0 for years in the range defined by 6100 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of 6101 // Jan 1 1970. This is required so that we don't run into integer 6102 // division of negative numbers. 6103 // c) there shouldn't be an overflow for 32-bit integers in the following 6104 // operations. 6105 static const int year_delta = 399999; 6106 static const int base_day = 365 * (1970 + year_delta) + 6107 (1970 + year_delta) / 4 - 6108 (1970 + year_delta) / 100 + 6109 (1970 + year_delta) / 400; 6110 6111 int year1 = year + year_delta; 6112 int day_from_year = 365 * year1 + 6113 year1 / 4 - 6114 year1 / 100 + 6115 year1 / 400 - 6116 base_day; 6117 6118 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) { 6119 return day_from_year + day_from_month[month] + day - 1; 6120 } 6121 6122 return day_from_year + day_from_month_leap[month] + day - 1; 6123} 6124 6125 6126static Object* Runtime_DateMakeDay(Arguments args) { 6127 NoHandleAllocation ha; 6128 ASSERT(args.length() == 3); 6129 6130 CONVERT_SMI_CHECKED(year, args[0]); 6131 CONVERT_SMI_CHECKED(month, args[1]); 6132 CONVERT_SMI_CHECKED(date, args[2]); 6133 6134 return Smi::FromInt(MakeDay(year, month, date)); 6135} 6136 6137 6138static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1}; 6139static const int kDaysIn4Years = 4 * 365 + 1; 6140static const int kDaysIn100Years = 25 * kDaysIn4Years - 1; 6141static const int kDaysIn400Years = 4 * kDaysIn100Years + 1; 6142static const int kDays1970to2000 = 30 * 365 + 7; 6143static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years - 6144 kDays1970to2000; 6145static const int kYearsOffset = 400000; 6146 6147static const char kDayInYear[] = { 6148 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6149 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6150 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6151 22, 23, 24, 25, 26, 27, 28, 6152 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6153 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6154 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6155 22, 23, 24, 25, 26, 27, 28, 29, 30, 6156 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6157 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6158 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6159 22, 23, 24, 25, 26, 27, 28, 29, 30, 6160 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6161 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6162 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6163 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6164 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6165 22, 23, 24, 25, 26, 27, 28, 29, 30, 6166 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6167 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6168 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6169 22, 23, 24, 25, 26, 27, 28, 29, 30, 6170 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6171 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6172 6173 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6174 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6175 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6176 22, 23, 24, 25, 26, 27, 28, 6177 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6178 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6179 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6180 22, 23, 24, 25, 26, 27, 28, 29, 30, 6181 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6182 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6183 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6184 22, 23, 24, 25, 26, 27, 28, 29, 30, 6185 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6186 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6187 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6188 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6189 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6190 22, 23, 24, 25, 26, 27, 28, 29, 30, 6191 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6192 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6193 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6194 22, 23, 24, 25, 26, 27, 28, 29, 30, 6195 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6196 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6197 6198 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6199 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6200 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6201 22, 23, 24, 25, 26, 27, 28, 29, 6202 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6203 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6204 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6205 22, 23, 24, 25, 26, 27, 28, 29, 30, 6206 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6207 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6208 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6209 22, 23, 24, 25, 26, 27, 28, 29, 30, 6210 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6211 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6212 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6213 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6214 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6215 22, 23, 24, 25, 26, 27, 28, 29, 30, 6216 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6217 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6218 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6219 22, 23, 24, 25, 26, 27, 28, 29, 30, 6220 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6221 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6222 6223 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6224 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6225 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6226 22, 23, 24, 25, 26, 27, 28, 6227 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6228 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6229 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6230 22, 23, 24, 25, 26, 27, 28, 29, 30, 6231 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6232 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6233 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6234 22, 23, 24, 25, 26, 27, 28, 29, 30, 6235 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6236 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6237 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6238 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6239 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6240 22, 23, 24, 25, 26, 27, 28, 29, 30, 6241 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6242 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 6243 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6244 22, 23, 24, 25, 26, 27, 28, 29, 30, 6245 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6246 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; 6247 6248static const char kMonthInYear[] = { 6249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6250 0, 0, 0, 0, 0, 0, 6251 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6252 1, 1, 1, 6253 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6254 2, 2, 2, 2, 2, 2, 6255 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6256 3, 3, 3, 3, 3, 6257 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6258 4, 4, 4, 4, 4, 4, 6259 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6260 5, 5, 5, 5, 5, 6261 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6262 6, 6, 6, 6, 6, 6, 6263 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6264 7, 7, 7, 7, 7, 7, 6265 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6266 8, 8, 8, 8, 8, 6267 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6268 9, 9, 9, 9, 9, 9, 6269 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6270 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6271 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6272 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6273 6274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6275 0, 0, 0, 0, 0, 0, 6276 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6277 1, 1, 1, 6278 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6279 2, 2, 2, 2, 2, 2, 6280 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6281 3, 3, 3, 3, 3, 6282 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6283 4, 4, 4, 4, 4, 4, 6284 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6285 5, 5, 5, 5, 5, 6286 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6287 6, 6, 6, 6, 6, 6, 6288 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6289 7, 7, 7, 7, 7, 7, 6290 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6291 8, 8, 8, 8, 8, 6292 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6293 9, 9, 9, 9, 9, 9, 6294 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6295 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6296 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6297 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6298 6299 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6300 0, 0, 0, 0, 0, 0, 6301 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6302 1, 1, 1, 1, 6303 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6304 2, 2, 2, 2, 2, 2, 6305 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6306 3, 3, 3, 3, 3, 6307 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6308 4, 4, 4, 4, 4, 4, 6309 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6310 5, 5, 5, 5, 5, 6311 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6312 6, 6, 6, 6, 6, 6, 6313 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6314 7, 7, 7, 7, 7, 7, 6315 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6316 8, 8, 8, 8, 8, 6317 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6318 9, 9, 9, 9, 9, 9, 6319 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6320 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6321 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6322 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6323 6324 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6325 0, 0, 0, 0, 0, 0, 6326 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6327 1, 1, 1, 6328 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6329 2, 2, 2, 2, 2, 2, 6330 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6331 3, 3, 3, 3, 3, 6332 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6333 4, 4, 4, 4, 4, 4, 6334 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6335 5, 5, 5, 5, 5, 6336 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6337 6, 6, 6, 6, 6, 6, 6338 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6339 7, 7, 7, 7, 7, 7, 6340 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6341 8, 8, 8, 8, 8, 6342 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6343 9, 9, 9, 9, 9, 9, 6344 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6345 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6346 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6347 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}; 6348 6349 6350// This function works for dates from 1970 to 2099. 6351static inline void DateYMDFromTimeAfter1970(int date, 6352 int& year, int& month, int& day) { 6353#ifdef DEBUG 6354 int save_date = date; // Need this for ASSERT in the end. 6355#endif 6356 6357 year = 1970 + (4 * date + 2) / kDaysIn4Years; 6358 date %= kDaysIn4Years; 6359 6360 month = kMonthInYear[date]; 6361 day = kDayInYear[date]; 6362 6363 ASSERT(MakeDay(year, month, day) == save_date); 6364} 6365 6366 6367static inline void DateYMDFromTimeSlow(int date, 6368 int& year, int& month, int& day) { 6369#ifdef DEBUG 6370 int save_date = date; // Need this for ASSERT in the end. 6371#endif 6372 6373 date += kDaysOffset; 6374 year = 400 * (date / kDaysIn400Years) - kYearsOffset; 6375 date %= kDaysIn400Years; 6376 6377 ASSERT(MakeDay(year, 0, 1) + date == save_date); 6378 6379 date--; 6380 int yd1 = date / kDaysIn100Years; 6381 date %= kDaysIn100Years; 6382 year += 100 * yd1; 6383 6384 date++; 6385 int yd2 = date / kDaysIn4Years; 6386 date %= kDaysIn4Years; 6387 year += 4 * yd2; 6388 6389 date--; 6390 int yd3 = date / 365; 6391 date %= 365; 6392 year += yd3; 6393 6394 bool is_leap = (!yd1 || yd2) && !yd3; 6395 6396 ASSERT(date >= -1); 6397 ASSERT(is_leap || (date >= 0)); 6398 ASSERT((date < 365) || (is_leap && (date < 366))); 6399 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0)))); 6400 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date)); 6401 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date)); 6402 6403 if (is_leap) { 6404 day = kDayInYear[2*365 + 1 + date]; 6405 month = kMonthInYear[2*365 + 1 + date]; 6406 } else { 6407 day = kDayInYear[date]; 6408 month = kMonthInYear[date]; 6409 } 6410 6411 ASSERT(MakeDay(year, month, day) == save_date); 6412} 6413 6414 6415static inline void DateYMDFromTime(int date, 6416 int& year, int& month, int& day) { 6417 if (date >= 0 && date < 32 * kDaysIn4Years) { 6418 DateYMDFromTimeAfter1970(date, year, month, day); 6419 } else { 6420 DateYMDFromTimeSlow(date, year, month, day); 6421 } 6422} 6423 6424 6425static Object* Runtime_DateYMDFromTime(Arguments args) { 6426 NoHandleAllocation ha; 6427 ASSERT(args.length() == 2); 6428 6429 CONVERT_DOUBLE_CHECKED(t, args[0]); 6430 CONVERT_CHECKED(JSArray, res_array, args[1]); 6431 6432 int year, month, day; 6433 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day); 6434 6435 res_array->SetElement(0, Smi::FromInt(year)); 6436 res_array->SetElement(1, Smi::FromInt(month)); 6437 res_array->SetElement(2, Smi::FromInt(day)); 6438 6439 return Heap::undefined_value(); 6440} 6441 6442 6443static Object* Runtime_NewArgumentsFast(Arguments args) { 6444 NoHandleAllocation ha; 6445 ASSERT(args.length() == 3); 6446 6447 JSFunction* callee = JSFunction::cast(args[0]); 6448 Object** parameters = reinterpret_cast<Object**>(args[1]); 6449 const int length = Smi::cast(args[2])->value(); 6450 6451 Object* result = Heap::AllocateArgumentsObject(callee, length); 6452 if (result->IsFailure()) return result; 6453 // Allocate the elements if needed. 6454 if (length > 0) { 6455 // Allocate the fixed array. 6456 Object* obj = Heap::AllocateRawFixedArray(length); 6457 if (obj->IsFailure()) return obj; 6458 6459 AssertNoAllocation no_gc; 6460 reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map()); 6461 FixedArray* array = FixedArray::cast(obj); 6462 array->set_length(length); 6463 6464 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); 6465 for (int i = 0; i < length; i++) { 6466 array->set(i, *--parameters, mode); 6467 } 6468 JSObject::cast(result)->set_elements(FixedArray::cast(obj)); 6469 } 6470 return result; 6471} 6472 6473 6474static Object* Runtime_NewClosure(Arguments args) { 6475 HandleScope scope; 6476 ASSERT(args.length() == 2); 6477 CONVERT_ARG_CHECKED(Context, context, 0); 6478 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1); 6479 6480 PretenureFlag pretenure = (context->global_context() == *context) 6481 ? TENURED // Allocate global closures in old space. 6482 : NOT_TENURED; // Allocate local closures in new space. 6483 Handle<JSFunction> result = 6484 Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure); 6485 return *result; 6486} 6487 6488 6489static Code* ComputeConstructStub(Handle<JSFunction> function) { 6490 Handle<Object> prototype = Factory::null_value(); 6491 if (function->has_instance_prototype()) { 6492 prototype = Handle<Object>(function->instance_prototype()); 6493 } 6494 if (function->shared()->CanGenerateInlineConstructor(*prototype)) { 6495 ConstructStubCompiler compiler; 6496 Object* code = compiler.CompileConstructStub(function->shared()); 6497 if (code->IsFailure()) { 6498 return Builtins::builtin(Builtins::JSConstructStubGeneric); 6499 } 6500 return Code::cast(code); 6501 } 6502 6503 return function->shared()->construct_stub(); 6504} 6505 6506 6507static Object* Runtime_NewObject(Arguments args) { 6508 HandleScope scope; 6509 ASSERT(args.length() == 1); 6510 6511 Handle<Object> constructor = args.at<Object>(0); 6512 6513 // If the constructor isn't a proper function we throw a type error. 6514 if (!constructor->IsJSFunction()) { 6515 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 6516 Handle<Object> type_error = 6517 Factory::NewTypeError("not_constructor", arguments); 6518 return Top::Throw(*type_error); 6519 } 6520 6521 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor); 6522 6523 // If function should not have prototype, construction is not allowed. In this 6524 // case generated code bailouts here, since function has no initial_map. 6525 if (!function->should_have_prototype()) { 6526 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 6527 Handle<Object> type_error = 6528 Factory::NewTypeError("not_constructor", arguments); 6529 return Top::Throw(*type_error); 6530 } 6531 6532#ifdef ENABLE_DEBUGGER_SUPPORT 6533 // Handle stepping into constructors if step into is active. 6534 if (Debug::StepInActive()) { 6535 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true); 6536 } 6537#endif 6538 6539 if (function->has_initial_map()) { 6540 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { 6541 // The 'Function' function ignores the receiver object when 6542 // called using 'new' and creates a new JSFunction object that 6543 // is returned. The receiver object is only used for error 6544 // reporting if an error occurs when constructing the new 6545 // JSFunction. Factory::NewJSObject() should not be used to 6546 // allocate JSFunctions since it does not properly initialize 6547 // the shared part of the function. Since the receiver is 6548 // ignored anyway, we use the global object as the receiver 6549 // instead of a new JSFunction object. This way, errors are 6550 // reported the same way whether or not 'Function' is called 6551 // using 'new'. 6552 return Top::context()->global(); 6553 } 6554 } 6555 6556 // The function should be compiled for the optimization hints to be available. 6557 Handle<SharedFunctionInfo> shared(function->shared()); 6558 EnsureCompiled(shared, CLEAR_EXCEPTION); 6559 6560 bool first_allocation = !function->has_initial_map(); 6561 Handle<JSObject> result = Factory::NewJSObject(function); 6562 if (first_allocation) { 6563 Handle<Code> stub = Handle<Code>( 6564 ComputeConstructStub(Handle<JSFunction>(function))); 6565 shared->set_construct_stub(*stub); 6566 } 6567 6568 Counters::constructed_objects.Increment(); 6569 Counters::constructed_objects_runtime.Increment(); 6570 6571 return *result; 6572} 6573 6574 6575static Object* Runtime_LazyCompile(Arguments args) { 6576 HandleScope scope; 6577 ASSERT(args.length() == 1); 6578 6579 Handle<JSFunction> function = args.at<JSFunction>(0); 6580#ifdef DEBUG 6581 if (FLAG_trace_lazy) { 6582 PrintF("[lazy: "); 6583 function->shared()->name()->Print(); 6584 PrintF("]\n"); 6585 } 6586#endif 6587 6588 // Compile the target function. Here we compile using CompileLazyInLoop in 6589 // order to get the optimized version. This helps code like delta-blue 6590 // that calls performance-critical routines through constructors. A 6591 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a 6592 // direct call. Since the in-loop tracking takes place through CallICs 6593 // this means that things called through constructors are never known to 6594 // be in loops. We compile them as if they are in loops here just in case. 6595 ASSERT(!function->is_compiled()); 6596 if (!CompileLazyInLoop(function, Handle<Object>::null(), KEEP_EXCEPTION)) { 6597 return Failure::Exception(); 6598 } 6599 6600 return function->code(); 6601} 6602 6603 6604static Object* Runtime_GetFunctionDelegate(Arguments args) { 6605 HandleScope scope; 6606 ASSERT(args.length() == 1); 6607 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 6608 return *Execution::GetFunctionDelegate(args.at<Object>(0)); 6609} 6610 6611 6612static Object* Runtime_GetConstructorDelegate(Arguments args) { 6613 HandleScope scope; 6614 ASSERT(args.length() == 1); 6615 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 6616 return *Execution::GetConstructorDelegate(args.at<Object>(0)); 6617} 6618 6619 6620static Object* Runtime_NewContext(Arguments args) { 6621 NoHandleAllocation ha; 6622 ASSERT(args.length() == 1); 6623 6624 CONVERT_CHECKED(JSFunction, function, args[0]); 6625 int length = ScopeInfo<>::NumberOfContextSlots(function->code()); 6626 Object* result = Heap::AllocateFunctionContext(length, function); 6627 if (result->IsFailure()) return result; 6628 6629 Top::set_context(Context::cast(result)); 6630 6631 return result; // non-failure 6632} 6633 6634static Object* PushContextHelper(Object* object, bool is_catch_context) { 6635 // Convert the object to a proper JavaScript object. 6636 Object* js_object = object; 6637 if (!js_object->IsJSObject()) { 6638 js_object = js_object->ToObject(); 6639 if (js_object->IsFailure()) { 6640 if (!Failure::cast(js_object)->IsInternalError()) return js_object; 6641 HandleScope scope; 6642 Handle<Object> handle(object); 6643 Handle<Object> result = 6644 Factory::NewTypeError("with_expression", HandleVector(&handle, 1)); 6645 return Top::Throw(*result); 6646 } 6647 } 6648 6649 Object* result = 6650 Heap::AllocateWithContext(Top::context(), 6651 JSObject::cast(js_object), 6652 is_catch_context); 6653 if (result->IsFailure()) return result; 6654 6655 Context* context = Context::cast(result); 6656 Top::set_context(context); 6657 6658 return result; 6659} 6660 6661 6662static Object* Runtime_PushContext(Arguments args) { 6663 NoHandleAllocation ha; 6664 ASSERT(args.length() == 1); 6665 return PushContextHelper(args[0], false); 6666} 6667 6668 6669static Object* Runtime_PushCatchContext(Arguments args) { 6670 NoHandleAllocation ha; 6671 ASSERT(args.length() == 1); 6672 return PushContextHelper(args[0], true); 6673} 6674 6675 6676static Object* Runtime_LookupContext(Arguments args) { 6677 HandleScope scope; 6678 ASSERT(args.length() == 2); 6679 6680 CONVERT_ARG_CHECKED(Context, context, 0); 6681 CONVERT_ARG_CHECKED(String, name, 1); 6682 6683 int index; 6684 PropertyAttributes attributes; 6685 ContextLookupFlags flags = FOLLOW_CHAINS; 6686 Handle<Object> holder = 6687 context->Lookup(name, flags, &index, &attributes); 6688 6689 if (index < 0 && !holder.is_null()) { 6690 ASSERT(holder->IsJSObject()); 6691 return *holder; 6692 } 6693 6694 // No intermediate context found. Use global object by default. 6695 return Top::context()->global(); 6696} 6697 6698 6699// A mechanism to return a pair of Object pointers in registers (if possible). 6700// How this is achieved is calling convention-dependent. 6701// All currently supported x86 compiles uses calling conventions that are cdecl 6702// variants where a 64-bit value is returned in two 32-bit registers 6703// (edx:eax on ia32, r1:r0 on ARM). 6704// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. 6705// In Win64 calling convention, a struct of two pointers is returned in memory, 6706// allocated by the caller, and passed as a pointer in a hidden first parameter. 6707#ifdef V8_HOST_ARCH_64_BIT 6708struct ObjectPair { 6709 Object* x; 6710 Object* y; 6711}; 6712 6713static inline ObjectPair MakePair(Object* x, Object* y) { 6714 ObjectPair result = {x, y}; 6715 // Pointers x and y returned in rax and rdx, in AMD-x64-abi. 6716 // In Win64 they are assigned to a hidden first argument. 6717 return result; 6718} 6719#else 6720typedef uint64_t ObjectPair; 6721static inline ObjectPair MakePair(Object* x, Object* y) { 6722 return reinterpret_cast<uint32_t>(x) | 6723 (reinterpret_cast<ObjectPair>(y) << 32); 6724} 6725#endif 6726 6727 6728static inline Object* Unhole(Object* x, PropertyAttributes attributes) { 6729 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); 6730 USE(attributes); 6731 return x->IsTheHole() ? Heap::undefined_value() : x; 6732} 6733 6734 6735static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) { 6736 ASSERT(!holder->IsGlobalObject()); 6737 Context* top = Top::context(); 6738 // Get the context extension function. 6739 JSFunction* context_extension_function = 6740 top->global_context()->context_extension_function(); 6741 // If the holder isn't a context extension object, we just return it 6742 // as the receiver. This allows arguments objects to be used as 6743 // receivers, but only if they are put in the context scope chain 6744 // explicitly via a with-statement. 6745 Object* constructor = holder->map()->constructor(); 6746 if (constructor != context_extension_function) return holder; 6747 // Fall back to using the global object as the receiver if the 6748 // property turns out to be a local variable allocated in a context 6749 // extension object - introduced via eval. 6750 return top->global()->global_receiver(); 6751} 6752 6753 6754static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) { 6755 HandleScope scope; 6756 ASSERT_EQ(2, args.length()); 6757 6758 if (!args[0]->IsContext() || !args[1]->IsString()) { 6759 return MakePair(Top::ThrowIllegalOperation(), NULL); 6760 } 6761 Handle<Context> context = args.at<Context>(0); 6762 Handle<String> name = args.at<String>(1); 6763 6764 int index; 6765 PropertyAttributes attributes; 6766 ContextLookupFlags flags = FOLLOW_CHAINS; 6767 Handle<Object> holder = 6768 context->Lookup(name, flags, &index, &attributes); 6769 6770 // If the index is non-negative, the slot has been found in a local 6771 // variable or a parameter. Read it from the context object or the 6772 // arguments object. 6773 if (index >= 0) { 6774 // If the "property" we were looking for is a local variable or an 6775 // argument in a context, the receiver is the global object; see 6776 // ECMA-262, 3rd., 10.1.6 and 10.2.3. 6777 JSObject* receiver = Top::context()->global()->global_receiver(); 6778 Object* value = (holder->IsContext()) 6779 ? Context::cast(*holder)->get(index) 6780 : JSObject::cast(*holder)->GetElement(index); 6781 return MakePair(Unhole(value, attributes), receiver); 6782 } 6783 6784 // If the holder is found, we read the property from it. 6785 if (!holder.is_null() && holder->IsJSObject()) { 6786 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name)); 6787 JSObject* object = JSObject::cast(*holder); 6788 JSObject* receiver; 6789 if (object->IsGlobalObject()) { 6790 receiver = GlobalObject::cast(object)->global_receiver(); 6791 } else if (context->is_exception_holder(*holder)) { 6792 receiver = Top::context()->global()->global_receiver(); 6793 } else { 6794 receiver = ComputeReceiverForNonGlobal(object); 6795 } 6796 // No need to unhole the value here. This is taken care of by the 6797 // GetProperty function. 6798 Object* value = object->GetProperty(*name); 6799 return MakePair(value, receiver); 6800 } 6801 6802 if (throw_error) { 6803 // The property doesn't exist - throw exception. 6804 Handle<Object> reference_error = 6805 Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); 6806 return MakePair(Top::Throw(*reference_error), NULL); 6807 } else { 6808 // The property doesn't exist - return undefined 6809 return MakePair(Heap::undefined_value(), Heap::undefined_value()); 6810 } 6811} 6812 6813 6814static ObjectPair Runtime_LoadContextSlot(Arguments args) { 6815 return LoadContextSlotHelper(args, true); 6816} 6817 6818 6819static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) { 6820 return LoadContextSlotHelper(args, false); 6821} 6822 6823 6824static Object* Runtime_StoreContextSlot(Arguments args) { 6825 HandleScope scope; 6826 ASSERT(args.length() == 3); 6827 6828 Handle<Object> value(args[0]); 6829 CONVERT_ARG_CHECKED(Context, context, 1); 6830 CONVERT_ARG_CHECKED(String, name, 2); 6831 6832 int index; 6833 PropertyAttributes attributes; 6834 ContextLookupFlags flags = FOLLOW_CHAINS; 6835 Handle<Object> holder = 6836 context->Lookup(name, flags, &index, &attributes); 6837 6838 if (index >= 0) { 6839 if (holder->IsContext()) { 6840 // Ignore if read_only variable. 6841 if ((attributes & READ_ONLY) == 0) { 6842 Handle<Context>::cast(holder)->set(index, *value); 6843 } 6844 } else { 6845 ASSERT((attributes & READ_ONLY) == 0); 6846 Object* result = 6847 Handle<JSObject>::cast(holder)->SetElement(index, *value); 6848 USE(result); 6849 ASSERT(!result->IsFailure()); 6850 } 6851 return *value; 6852 } 6853 6854 // Slow case: The property is not in a FixedArray context. 6855 // It is either in an JSObject extension context or it was not found. 6856 Handle<JSObject> context_ext; 6857 6858 if (!holder.is_null()) { 6859 // The property exists in the extension context. 6860 context_ext = Handle<JSObject>::cast(holder); 6861 } else { 6862 // The property was not found. It needs to be stored in the global context. 6863 ASSERT(attributes == ABSENT); 6864 attributes = NONE; 6865 context_ext = Handle<JSObject>(Top::context()->global()); 6866 } 6867 6868 // Set the property, but ignore if read_only variable on the context 6869 // extension object itself. 6870 if ((attributes & READ_ONLY) == 0 || 6871 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { 6872 Handle<Object> set = SetProperty(context_ext, name, value, attributes); 6873 if (set.is_null()) { 6874 // Failure::Exception is converted to a null handle in the 6875 // handle-based methods such as SetProperty. We therefore need 6876 // to convert null handles back to exceptions. 6877 ASSERT(Top::has_pending_exception()); 6878 return Failure::Exception(); 6879 } 6880 } 6881 return *value; 6882} 6883 6884 6885static Object* Runtime_Throw(Arguments args) { 6886 HandleScope scope; 6887 ASSERT(args.length() == 1); 6888 6889 return Top::Throw(args[0]); 6890} 6891 6892 6893static Object* Runtime_ReThrow(Arguments args) { 6894 HandleScope scope; 6895 ASSERT(args.length() == 1); 6896 6897 return Top::ReThrow(args[0]); 6898} 6899 6900 6901static Object* Runtime_PromoteScheduledException(Arguments args) { 6902 ASSERT_EQ(0, args.length()); 6903 return Top::PromoteScheduledException(); 6904} 6905 6906 6907static Object* Runtime_ThrowReferenceError(Arguments args) { 6908 HandleScope scope; 6909 ASSERT(args.length() == 1); 6910 6911 Handle<Object> name(args[0]); 6912 Handle<Object> reference_error = 6913 Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); 6914 return Top::Throw(*reference_error); 6915} 6916 6917 6918static Object* Runtime_StackOverflow(Arguments args) { 6919 NoHandleAllocation na; 6920 return Top::StackOverflow(); 6921} 6922 6923 6924static Object* Runtime_StackGuard(Arguments args) { 6925 ASSERT(args.length() == 1); 6926 6927 // First check if this is a real stack overflow. 6928 if (StackGuard::IsStackOverflow()) { 6929 return Runtime_StackOverflow(args); 6930 } 6931 6932 return Execution::HandleStackGuardInterrupt(); 6933} 6934 6935 6936// NOTE: These PrintXXX functions are defined for all builds (not just 6937// DEBUG builds) because we may want to be able to trace function 6938// calls in all modes. 6939static void PrintString(String* str) { 6940 // not uncommon to have empty strings 6941 if (str->length() > 0) { 6942 SmartPointer<char> s = 6943 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 6944 PrintF("%s", *s); 6945 } 6946} 6947 6948 6949static void PrintObject(Object* obj) { 6950 if (obj->IsSmi()) { 6951 PrintF("%d", Smi::cast(obj)->value()); 6952 } else if (obj->IsString() || obj->IsSymbol()) { 6953 PrintString(String::cast(obj)); 6954 } else if (obj->IsNumber()) { 6955 PrintF("%g", obj->Number()); 6956 } else if (obj->IsFailure()) { 6957 PrintF("<failure>"); 6958 } else if (obj->IsUndefined()) { 6959 PrintF("<undefined>"); 6960 } else if (obj->IsNull()) { 6961 PrintF("<null>"); 6962 } else if (obj->IsTrue()) { 6963 PrintF("<true>"); 6964 } else if (obj->IsFalse()) { 6965 PrintF("<false>"); 6966 } else { 6967 PrintF("%p", obj); 6968 } 6969} 6970 6971 6972static int StackSize() { 6973 int n = 0; 6974 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++; 6975 return n; 6976} 6977 6978 6979static void PrintTransition(Object* result) { 6980 // indentation 6981 { const int nmax = 80; 6982 int n = StackSize(); 6983 if (n <= nmax) 6984 PrintF("%4d:%*s", n, n, ""); 6985 else 6986 PrintF("%4d:%*s", n, nmax, "..."); 6987 } 6988 6989 if (result == NULL) { 6990 // constructor calls 6991 JavaScriptFrameIterator it; 6992 JavaScriptFrame* frame = it.frame(); 6993 if (frame->IsConstructor()) PrintF("new "); 6994 // function name 6995 Object* fun = frame->function(); 6996 if (fun->IsJSFunction()) { 6997 PrintObject(JSFunction::cast(fun)->shared()->name()); 6998 } else { 6999 PrintObject(fun); 7000 } 7001 // function arguments 7002 // (we are intentionally only printing the actually 7003 // supplied parameters, not all parameters required) 7004 PrintF("(this="); 7005 PrintObject(frame->receiver()); 7006 const int length = frame->GetProvidedParametersCount(); 7007 for (int i = 0; i < length; i++) { 7008 PrintF(", "); 7009 PrintObject(frame->GetParameter(i)); 7010 } 7011 PrintF(") {\n"); 7012 7013 } else { 7014 // function result 7015 PrintF("} -> "); 7016 PrintObject(result); 7017 PrintF("\n"); 7018 } 7019} 7020 7021 7022static Object* Runtime_TraceEnter(Arguments args) { 7023 ASSERT(args.length() == 0); 7024 NoHandleAllocation ha; 7025 PrintTransition(NULL); 7026 return Heap::undefined_value(); 7027} 7028 7029 7030static Object* Runtime_TraceExit(Arguments args) { 7031 NoHandleAllocation ha; 7032 PrintTransition(args[0]); 7033 return args[0]; // return TOS 7034} 7035 7036 7037static Object* Runtime_DebugPrint(Arguments args) { 7038 NoHandleAllocation ha; 7039 ASSERT(args.length() == 1); 7040 7041#ifdef DEBUG 7042 if (args[0]->IsString()) { 7043 // If we have a string, assume it's a code "marker" 7044 // and print some interesting cpu debugging info. 7045 JavaScriptFrameIterator it; 7046 JavaScriptFrame* frame = it.frame(); 7047 PrintF("fp = %p, sp = %p, caller_sp = %p: ", 7048 frame->fp(), frame->sp(), frame->caller_sp()); 7049 } else { 7050 PrintF("DebugPrint: "); 7051 } 7052 args[0]->Print(); 7053 if (args[0]->IsHeapObject()) { 7054 PrintF("\n"); 7055 HeapObject::cast(args[0])->map()->Print(); 7056 } 7057#else 7058 // ShortPrint is available in release mode. Print is not. 7059 args[0]->ShortPrint(); 7060#endif 7061 PrintF("\n"); 7062 Flush(); 7063 7064 return args[0]; // return TOS 7065} 7066 7067 7068static Object* Runtime_DebugTrace(Arguments args) { 7069 ASSERT(args.length() == 0); 7070 NoHandleAllocation ha; 7071 Top::PrintStack(); 7072 return Heap::undefined_value(); 7073} 7074 7075 7076static Object* Runtime_DateCurrentTime(Arguments args) { 7077 NoHandleAllocation ha; 7078 ASSERT(args.length() == 0); 7079 7080 // According to ECMA-262, section 15.9.1, page 117, the precision of 7081 // the number in a Date object representing a particular instant in 7082 // time is milliseconds. Therefore, we floor the result of getting 7083 // the OS time. 7084 double millis = floor(OS::TimeCurrentMillis()); 7085 return Heap::NumberFromDouble(millis); 7086} 7087 7088 7089static Object* Runtime_DateParseString(Arguments args) { 7090 HandleScope scope; 7091 ASSERT(args.length() == 2); 7092 7093 CONVERT_ARG_CHECKED(String, str, 0); 7094 FlattenString(str); 7095 7096 CONVERT_ARG_CHECKED(JSArray, output, 1); 7097 RUNTIME_ASSERT(output->HasFastElements()); 7098 7099 AssertNoAllocation no_allocation; 7100 7101 FixedArray* output_array = FixedArray::cast(output->elements()); 7102 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); 7103 bool result; 7104 if (str->IsAsciiRepresentation()) { 7105 result = DateParser::Parse(str->ToAsciiVector(), output_array); 7106 } else { 7107 ASSERT(str->IsTwoByteRepresentation()); 7108 result = DateParser::Parse(str->ToUC16Vector(), output_array); 7109 } 7110 7111 if (result) { 7112 return *output; 7113 } else { 7114 return Heap::null_value(); 7115 } 7116} 7117 7118 7119static Object* Runtime_DateLocalTimezone(Arguments args) { 7120 NoHandleAllocation ha; 7121 ASSERT(args.length() == 1); 7122 7123 CONVERT_DOUBLE_CHECKED(x, args[0]); 7124 const char* zone = OS::LocalTimezone(x); 7125 return Heap::AllocateStringFromUtf8(CStrVector(zone)); 7126} 7127 7128 7129static Object* Runtime_DateLocalTimeOffset(Arguments args) { 7130 NoHandleAllocation ha; 7131 ASSERT(args.length() == 0); 7132 7133 return Heap::NumberFromDouble(OS::LocalTimeOffset()); 7134} 7135 7136 7137static Object* Runtime_DateDaylightSavingsOffset(Arguments args) { 7138 NoHandleAllocation ha; 7139 ASSERT(args.length() == 1); 7140 7141 CONVERT_DOUBLE_CHECKED(x, args[0]); 7142 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x)); 7143} 7144 7145 7146static Object* Runtime_GlobalReceiver(Arguments args) { 7147 ASSERT(args.length() == 1); 7148 Object* global = args[0]; 7149 if (!global->IsJSGlobalObject()) return Heap::null_value(); 7150 return JSGlobalObject::cast(global)->global_receiver(); 7151} 7152 7153 7154static Object* Runtime_CompileString(Arguments args) { 7155 HandleScope scope; 7156 ASSERT_EQ(2, args.length()); 7157 CONVERT_ARG_CHECKED(String, source, 0); 7158 CONVERT_ARG_CHECKED(Oddball, is_json, 1) 7159 7160 // Compile source string in the global context. 7161 Handle<Context> context(Top::context()->global_context()); 7162 Compiler::ValidationState validate = (is_json->IsTrue()) 7163 ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON; 7164 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source, 7165 context, 7166 true, 7167 validate); 7168 if (shared.is_null()) return Failure::Exception(); 7169 Handle<JSFunction> fun = 7170 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED); 7171 return *fun; 7172} 7173 7174 7175static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) { 7176 ASSERT(args.length() == 3); 7177 if (!args[0]->IsJSFunction()) { 7178 return MakePair(Top::ThrowIllegalOperation(), NULL); 7179 } 7180 7181 HandleScope scope; 7182 Handle<JSFunction> callee = args.at<JSFunction>(0); 7183 Handle<Object> receiver; // Will be overwritten. 7184 7185 // Compute the calling context. 7186 Handle<Context> context = Handle<Context>(Top::context()); 7187#ifdef DEBUG 7188 // Make sure Top::context() agrees with the old code that traversed 7189 // the stack frames to compute the context. 7190 StackFrameLocator locator; 7191 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 7192 ASSERT(Context::cast(frame->context()) == *context); 7193#endif 7194 7195 // Find where the 'eval' symbol is bound. It is unaliased only if 7196 // it is bound in the global context. 7197 int index = -1; 7198 PropertyAttributes attributes = ABSENT; 7199 while (true) { 7200 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN, 7201 &index, &attributes); 7202 // Stop search when eval is found or when the global context is 7203 // reached. 7204 if (attributes != ABSENT || context->IsGlobalContext()) break; 7205 if (context->is_function_context()) { 7206 context = Handle<Context>(Context::cast(context->closure()->context())); 7207 } else { 7208 context = Handle<Context>(context->previous()); 7209 } 7210 } 7211 7212 // If eval could not be resolved, it has been deleted and we need to 7213 // throw a reference error. 7214 if (attributes == ABSENT) { 7215 Handle<Object> name = Factory::eval_symbol(); 7216 Handle<Object> reference_error = 7217 Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); 7218 return MakePair(Top::Throw(*reference_error), NULL); 7219 } 7220 7221 if (!context->IsGlobalContext()) { 7222 // 'eval' is not bound in the global context. Just call the function 7223 // with the given arguments. This is not necessarily the global eval. 7224 if (receiver->IsContext()) { 7225 context = Handle<Context>::cast(receiver); 7226 receiver = Handle<Object>(context->get(index)); 7227 } else if (receiver->IsJSContextExtensionObject()) { 7228 receiver = Handle<JSObject>(Top::context()->global()->global_receiver()); 7229 } 7230 return MakePair(*callee, *receiver); 7231 } 7232 7233 // 'eval' is bound in the global context, but it may have been overwritten. 7234 // Compare it to the builtin 'GlobalEval' function to make sure. 7235 if (*callee != Top::global_context()->global_eval_fun() || 7236 !args[1]->IsString()) { 7237 return MakePair(*callee, Top::context()->global()->global_receiver()); 7238 } 7239 7240 // Deal with a normal eval call with a string argument. Compile it 7241 // and return the compiled function bound in the local context. 7242 Handle<String> source = args.at<String>(1); 7243 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 7244 source, 7245 Handle<Context>(Top::context()), 7246 Top::context()->IsGlobalContext(), 7247 Compiler::DONT_VALIDATE_JSON); 7248 if (shared.is_null()) return MakePair(Failure::Exception(), NULL); 7249 callee = Factory::NewFunctionFromSharedFunctionInfo( 7250 shared, 7251 Handle<Context>(Top::context()), 7252 NOT_TENURED); 7253 return MakePair(*callee, args[2]); 7254} 7255 7256 7257static Object* Runtime_SetNewFunctionAttributes(Arguments args) { 7258 // This utility adjusts the property attributes for newly created Function 7259 // object ("new Function(...)") by changing the map. 7260 // All it does is changing the prototype property to enumerable 7261 // as specified in ECMA262, 15.3.5.2. 7262 HandleScope scope; 7263 ASSERT(args.length() == 1); 7264 CONVERT_ARG_CHECKED(JSFunction, func, 0); 7265 ASSERT(func->map()->instance_type() == 7266 Top::function_instance_map()->instance_type()); 7267 ASSERT(func->map()->instance_size() == 7268 Top::function_instance_map()->instance_size()); 7269 func->set_map(*Top::function_instance_map()); 7270 return *func; 7271} 7272 7273 7274// Push an array unto an array of arrays if it is not already in the 7275// array. Returns true if the element was pushed on the stack and 7276// false otherwise. 7277static Object* Runtime_PushIfAbsent(Arguments args) { 7278 ASSERT(args.length() == 2); 7279 CONVERT_CHECKED(JSArray, array, args[0]); 7280 CONVERT_CHECKED(JSArray, element, args[1]); 7281 RUNTIME_ASSERT(array->HasFastElements()); 7282 int length = Smi::cast(array->length())->value(); 7283 FixedArray* elements = FixedArray::cast(array->elements()); 7284 for (int i = 0; i < length; i++) { 7285 if (elements->get(i) == element) return Heap::false_value(); 7286 } 7287 Object* obj = array->SetFastElement(length, element); 7288 if (obj->IsFailure()) return obj; 7289 return Heap::true_value(); 7290} 7291 7292 7293/** 7294 * A simple visitor visits every element of Array's. 7295 * The backend storage can be a fixed array for fast elements case, 7296 * or a dictionary for sparse array. Since Dictionary is a subtype 7297 * of FixedArray, the class can be used by both fast and slow cases. 7298 * The second parameter of the constructor, fast_elements, specifies 7299 * whether the storage is a FixedArray or Dictionary. 7300 * 7301 * An index limit is used to deal with the situation that a result array 7302 * length overflows 32-bit non-negative integer. 7303 */ 7304class ArrayConcatVisitor { 7305 public: 7306 ArrayConcatVisitor(Handle<FixedArray> storage, 7307 uint32_t index_limit, 7308 bool fast_elements) : 7309 storage_(storage), index_limit_(index_limit), 7310 index_offset_(0), fast_elements_(fast_elements) { } 7311 7312 void visit(uint32_t i, Handle<Object> elm) { 7313 if (i >= index_limit_ - index_offset_) return; 7314 uint32_t index = index_offset_ + i; 7315 7316 if (fast_elements_) { 7317 ASSERT(index < static_cast<uint32_t>(storage_->length())); 7318 storage_->set(index, *elm); 7319 7320 } else { 7321 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_); 7322 Handle<NumberDictionary> result = 7323 Factory::DictionaryAtNumberPut(dict, index, elm); 7324 if (!result.is_identical_to(dict)) 7325 storage_ = result; 7326 } 7327 } 7328 7329 void increase_index_offset(uint32_t delta) { 7330 if (index_limit_ - index_offset_ < delta) { 7331 index_offset_ = index_limit_; 7332 } else { 7333 index_offset_ += delta; 7334 } 7335 } 7336 7337 Handle<FixedArray> storage() { return storage_; } 7338 7339 private: 7340 Handle<FixedArray> storage_; 7341 // Limit on the accepted indices. Elements with indices larger than the 7342 // limit are ignored by the visitor. 7343 uint32_t index_limit_; 7344 // Index after last seen index. Always less than or equal to index_limit_. 7345 uint32_t index_offset_; 7346 bool fast_elements_; 7347}; 7348 7349 7350template<class ExternalArrayClass, class ElementType> 7351static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver, 7352 bool elements_are_ints, 7353 bool elements_are_guaranteed_smis, 7354 uint32_t range, 7355 ArrayConcatVisitor* visitor) { 7356 Handle<ExternalArrayClass> array( 7357 ExternalArrayClass::cast(receiver->elements())); 7358 uint32_t len = Min(static_cast<uint32_t>(array->length()), range); 7359 7360 if (visitor != NULL) { 7361 if (elements_are_ints) { 7362 if (elements_are_guaranteed_smis) { 7363 for (uint32_t j = 0; j < len; j++) { 7364 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j)))); 7365 visitor->visit(j, e); 7366 } 7367 } else { 7368 for (uint32_t j = 0; j < len; j++) { 7369 int64_t val = static_cast<int64_t>(array->get(j)); 7370 if (Smi::IsValid(static_cast<intptr_t>(val))) { 7371 Handle<Smi> e(Smi::FromInt(static_cast<int>(val))); 7372 visitor->visit(j, e); 7373 } else { 7374 Handle<Object> e( 7375 Heap::AllocateHeapNumber(static_cast<ElementType>(val))); 7376 visitor->visit(j, e); 7377 } 7378 } 7379 } 7380 } else { 7381 for (uint32_t j = 0; j < len; j++) { 7382 Handle<Object> e(Heap::AllocateHeapNumber(array->get(j))); 7383 visitor->visit(j, e); 7384 } 7385 } 7386 } 7387 7388 return len; 7389} 7390 7391/** 7392 * A helper function that visits elements of a JSObject. Only elements 7393 * whose index between 0 and range (exclusive) are visited. 7394 * 7395 * If the third parameter, visitor, is not NULL, the visitor is called 7396 * with parameters, 'visitor_index_offset + element index' and the element. 7397 * 7398 * It returns the number of visisted elements. 7399 */ 7400static uint32_t IterateElements(Handle<JSObject> receiver, 7401 uint32_t range, 7402 ArrayConcatVisitor* visitor) { 7403 uint32_t num_of_elements = 0; 7404 7405 switch (receiver->GetElementsKind()) { 7406 case JSObject::FAST_ELEMENTS: { 7407 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 7408 uint32_t len = elements->length(); 7409 if (range < len) { 7410 len = range; 7411 } 7412 7413 for (uint32_t j = 0; j < len; j++) { 7414 Handle<Object> e(elements->get(j)); 7415 if (!e->IsTheHole()) { 7416 num_of_elements++; 7417 if (visitor) { 7418 visitor->visit(j, e); 7419 } 7420 } 7421 } 7422 break; 7423 } 7424 case JSObject::PIXEL_ELEMENTS: { 7425 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements())); 7426 uint32_t len = pixels->length(); 7427 if (range < len) { 7428 len = range; 7429 } 7430 7431 for (uint32_t j = 0; j < len; j++) { 7432 num_of_elements++; 7433 if (visitor != NULL) { 7434 Handle<Smi> e(Smi::FromInt(pixels->get(j))); 7435 visitor->visit(j, e); 7436 } 7437 } 7438 break; 7439 } 7440 case JSObject::EXTERNAL_BYTE_ELEMENTS: { 7441 num_of_elements = 7442 IterateExternalArrayElements<ExternalByteArray, int8_t>( 7443 receiver, true, true, range, visitor); 7444 break; 7445 } 7446 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 7447 num_of_elements = 7448 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( 7449 receiver, true, true, range, visitor); 7450 break; 7451 } 7452 case JSObject::EXTERNAL_SHORT_ELEMENTS: { 7453 num_of_elements = 7454 IterateExternalArrayElements<ExternalShortArray, int16_t>( 7455 receiver, true, true, range, visitor); 7456 break; 7457 } 7458 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 7459 num_of_elements = 7460 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( 7461 receiver, true, true, range, visitor); 7462 break; 7463 } 7464 case JSObject::EXTERNAL_INT_ELEMENTS: { 7465 num_of_elements = 7466 IterateExternalArrayElements<ExternalIntArray, int32_t>( 7467 receiver, true, false, range, visitor); 7468 break; 7469 } 7470 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { 7471 num_of_elements = 7472 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( 7473 receiver, true, false, range, visitor); 7474 break; 7475 } 7476 case JSObject::EXTERNAL_FLOAT_ELEMENTS: { 7477 num_of_elements = 7478 IterateExternalArrayElements<ExternalFloatArray, float>( 7479 receiver, false, false, range, visitor); 7480 break; 7481 } 7482 case JSObject::DICTIONARY_ELEMENTS: { 7483 Handle<NumberDictionary> dict(receiver->element_dictionary()); 7484 uint32_t capacity = dict->Capacity(); 7485 for (uint32_t j = 0; j < capacity; j++) { 7486 Handle<Object> k(dict->KeyAt(j)); 7487 if (dict->IsKey(*k)) { 7488 ASSERT(k->IsNumber()); 7489 uint32_t index = static_cast<uint32_t>(k->Number()); 7490 if (index < range) { 7491 num_of_elements++; 7492 if (visitor) { 7493 visitor->visit(index, Handle<Object>(dict->ValueAt(j))); 7494 } 7495 } 7496 } 7497 } 7498 break; 7499 } 7500 default: 7501 UNREACHABLE(); 7502 break; 7503 } 7504 7505 return num_of_elements; 7506} 7507 7508 7509/** 7510 * A helper function that visits elements of an Array object, and elements 7511 * on its prototypes. 7512 * 7513 * Elements on prototypes are visited first, and only elements whose indices 7514 * less than Array length are visited. 7515 * 7516 * If a ArrayConcatVisitor object is given, the visitor is called with 7517 * parameters, element's index + visitor_index_offset and the element. 7518 * 7519 * The returned number of elements is an upper bound on the actual number 7520 * of elements added. If the same element occurs in more than one object 7521 * in the array's prototype chain, it will be counted more than once, but 7522 * will only occur once in the result. 7523 */ 7524static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array, 7525 ArrayConcatVisitor* visitor) { 7526 uint32_t range = static_cast<uint32_t>(array->length()->Number()); 7527 Handle<Object> obj = array; 7528 7529 static const int kEstimatedPrototypes = 3; 7530 List< Handle<JSObject> > objects(kEstimatedPrototypes); 7531 7532 // Visit prototype first. If an element on the prototype is shadowed by 7533 // the inheritor using the same index, the ArrayConcatVisitor visits 7534 // the prototype element before the shadowing element. 7535 // The visitor can simply overwrite the old value by new value using 7536 // the same index. This follows Array::concat semantics. 7537 while (!obj->IsNull()) { 7538 objects.Add(Handle<JSObject>::cast(obj)); 7539 obj = Handle<Object>(obj->GetPrototype()); 7540 } 7541 7542 uint32_t nof_elements = 0; 7543 for (int i = objects.length() - 1; i >= 0; i--) { 7544 Handle<JSObject> obj = objects[i]; 7545 uint32_t encountered_elements = 7546 IterateElements(Handle<JSObject>::cast(obj), range, visitor); 7547 7548 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) { 7549 nof_elements = JSObject::kMaxElementCount; 7550 } else { 7551 nof_elements += encountered_elements; 7552 } 7553 } 7554 7555 return nof_elements; 7556} 7557 7558 7559/** 7560 * A helper function of Runtime_ArrayConcat. 7561 * 7562 * The first argument is an Array of arrays and objects. It is the 7563 * same as the arguments array of Array::concat JS function. 7564 * 7565 * If an argument is an Array object, the function visits array 7566 * elements. If an argument is not an Array object, the function 7567 * visits the object as if it is an one-element array. 7568 * 7569 * If the result array index overflows 32-bit unsigned integer, the rounded 7570 * non-negative number is used as new length. For example, if one 7571 * array length is 2^32 - 1, second array length is 1, the 7572 * concatenated array length is 0. 7573 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length 7574 * is one more than the last array index to get a value assigned). 7575 */ 7576static uint32_t IterateArguments(Handle<JSArray> arguments, 7577 ArrayConcatVisitor* visitor) { 7578 uint32_t visited_elements = 0; 7579 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 7580 7581 for (uint32_t i = 0; i < num_of_args; i++) { 7582 Handle<Object> obj(arguments->GetElement(i)); 7583 if (obj->IsJSArray()) { 7584 Handle<JSArray> array = Handle<JSArray>::cast(obj); 7585 uint32_t len = static_cast<uint32_t>(array->length()->Number()); 7586 uint32_t nof_elements = 7587 IterateArrayAndPrototypeElements(array, visitor); 7588 // Total elements of array and its prototype chain can be more than 7589 // the array length, but ArrayConcat can only concatenate at most 7590 // the array length number of elements. We use the length as an estimate 7591 // for the actual number of elements added. 7592 uint32_t added_elements = (nof_elements > len) ? len : nof_elements; 7593 if (JSArray::kMaxElementCount - visited_elements < added_elements) { 7594 visited_elements = JSArray::kMaxElementCount; 7595 } else { 7596 visited_elements += added_elements; 7597 } 7598 if (visitor) visitor->increase_index_offset(len); 7599 } else { 7600 if (visitor) { 7601 visitor->visit(0, obj); 7602 visitor->increase_index_offset(1); 7603 } 7604 if (visited_elements < JSArray::kMaxElementCount) { 7605 visited_elements++; 7606 } 7607 } 7608 } 7609 return visited_elements; 7610} 7611 7612 7613/** 7614 * Array::concat implementation. 7615 * See ECMAScript 262, 15.4.4.4. 7616 * TODO(lrn): Fix non-compliance for very large concatenations and update to 7617 * following the ECMAScript 5 specification. 7618 */ 7619static Object* Runtime_ArrayConcat(Arguments args) { 7620 ASSERT(args.length() == 1); 7621 HandleScope handle_scope; 7622 7623 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); 7624 Handle<JSArray> arguments(arg_arrays); 7625 7626 // Pass 1: estimate the number of elements of the result 7627 // (it could be more than real numbers if prototype has elements). 7628 uint32_t result_length = 0; 7629 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 7630 7631 { AssertNoAllocation nogc; 7632 for (uint32_t i = 0; i < num_of_args; i++) { 7633 Object* obj = arguments->GetElement(i); 7634 uint32_t length_estimate; 7635 if (obj->IsJSArray()) { 7636 length_estimate = 7637 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); 7638 } else { 7639 length_estimate = 1; 7640 } 7641 if (JSObject::kMaxElementCount - result_length < length_estimate) { 7642 result_length = JSObject::kMaxElementCount; 7643 break; 7644 } 7645 result_length += length_estimate; 7646 } 7647 } 7648 7649 // Allocate an empty array, will set length and content later. 7650 Handle<JSArray> result = Factory::NewJSArray(0); 7651 7652 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL); 7653 // If estimated number of elements is more than half of length, a 7654 // fixed array (fast case) is more time and space-efficient than a 7655 // dictionary. 7656 bool fast_case = (estimate_nof_elements * 2) >= result_length; 7657 7658 Handle<FixedArray> storage; 7659 if (fast_case) { 7660 // The backing storage array must have non-existing elements to 7661 // preserve holes across concat operations. 7662 storage = Factory::NewFixedArrayWithHoles(result_length); 7663 7664 } else { 7665 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 7666 uint32_t at_least_space_for = estimate_nof_elements + 7667 (estimate_nof_elements >> 2); 7668 storage = Handle<FixedArray>::cast( 7669 Factory::NewNumberDictionary(at_least_space_for)); 7670 } 7671 7672 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length)); 7673 7674 ArrayConcatVisitor visitor(storage, result_length, fast_case); 7675 7676 IterateArguments(arguments, &visitor); 7677 7678 result->set_length(*len); 7679 // Please note the storage might have changed in the visitor. 7680 result->set_elements(*visitor.storage()); 7681 7682 return *result; 7683} 7684 7685 7686// This will not allocate (flatten the string), but it may run 7687// very slowly for very deeply nested ConsStrings. For debugging use only. 7688static Object* Runtime_GlobalPrint(Arguments args) { 7689 NoHandleAllocation ha; 7690 ASSERT(args.length() == 1); 7691 7692 CONVERT_CHECKED(String, string, args[0]); 7693 StringInputBuffer buffer(string); 7694 while (buffer.has_more()) { 7695 uint16_t character = buffer.GetNext(); 7696 PrintF("%c", character); 7697 } 7698 return string; 7699} 7700 7701// Moves all own elements of an object, that are below a limit, to positions 7702// starting at zero. All undefined values are placed after non-undefined values, 7703// and are followed by non-existing element. Does not change the length 7704// property. 7705// Returns the number of non-undefined elements collected. 7706static Object* Runtime_RemoveArrayHoles(Arguments args) { 7707 ASSERT(args.length() == 2); 7708 CONVERT_CHECKED(JSObject, object, args[0]); 7709 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 7710 return object->PrepareElementsForSort(limit); 7711} 7712 7713 7714// Move contents of argument 0 (an array) to argument 1 (an array) 7715static Object* Runtime_MoveArrayContents(Arguments args) { 7716 ASSERT(args.length() == 2); 7717 CONVERT_CHECKED(JSArray, from, args[0]); 7718 CONVERT_CHECKED(JSArray, to, args[1]); 7719 to->SetContent(FixedArray::cast(from->elements())); 7720 to->set_length(from->length()); 7721 from->SetContent(Heap::empty_fixed_array()); 7722 from->set_length(Smi::FromInt(0)); 7723 return to; 7724} 7725 7726 7727// How many elements does this array have? 7728static Object* Runtime_EstimateNumberOfElements(Arguments args) { 7729 ASSERT(args.length() == 1); 7730 CONVERT_CHECKED(JSArray, array, args[0]); 7731 HeapObject* elements = array->elements(); 7732 if (elements->IsDictionary()) { 7733 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements()); 7734 } else { 7735 return array->length(); 7736 } 7737} 7738 7739 7740static Object* Runtime_SwapElements(Arguments args) { 7741 HandleScope handle_scope; 7742 7743 ASSERT_EQ(3, args.length()); 7744 7745 CONVERT_ARG_CHECKED(JSObject, object, 0); 7746 Handle<Object> key1 = args.at<Object>(1); 7747 Handle<Object> key2 = args.at<Object>(2); 7748 7749 uint32_t index1, index2; 7750 if (!Array::IndexFromObject(*key1, &index1) 7751 || !Array::IndexFromObject(*key2, &index2)) { 7752 return Top::ThrowIllegalOperation(); 7753 } 7754 7755 Handle<JSObject> jsobject = Handle<JSObject>::cast(object); 7756 Handle<Object> tmp1 = GetElement(jsobject, index1); 7757 Handle<Object> tmp2 = GetElement(jsobject, index2); 7758 7759 SetElement(jsobject, index1, tmp2); 7760 SetElement(jsobject, index2, tmp1); 7761 7762 return Heap::undefined_value(); 7763} 7764 7765 7766// Returns an array that tells you where in the [0, length) interval an array 7767// might have elements. Can either return keys or intervals. Keys can have 7768// gaps in (undefined). Intervals can also span over some undefined keys. 7769static Object* Runtime_GetArrayKeys(Arguments args) { 7770 ASSERT(args.length() == 2); 7771 HandleScope scope; 7772 CONVERT_ARG_CHECKED(JSObject, array, 0); 7773 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); 7774 if (array->elements()->IsDictionary()) { 7775 // Create an array and get all the keys into it, then remove all the 7776 // keys that are not integers in the range 0 to length-1. 7777 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS); 7778 int keys_length = keys->length(); 7779 for (int i = 0; i < keys_length; i++) { 7780 Object* key = keys->get(i); 7781 uint32_t index; 7782 if (!Array::IndexFromObject(key, &index) || index >= length) { 7783 // Zap invalid keys. 7784 keys->set_undefined(i); 7785 } 7786 } 7787 return *Factory::NewJSArrayWithElements(keys); 7788 } else { 7789 Handle<FixedArray> single_interval = Factory::NewFixedArray(2); 7790 // -1 means start of array. 7791 single_interval->set(0, Smi::FromInt(-1)); 7792 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); 7793 uint32_t min_length = actual_length < length ? actual_length : length; 7794 Handle<Object> length_object = 7795 Factory::NewNumber(static_cast<double>(min_length)); 7796 single_interval->set(1, *length_object); 7797 return *Factory::NewJSArrayWithElements(single_interval); 7798 } 7799} 7800 7801 7802// DefineAccessor takes an optional final argument which is the 7803// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due 7804// to the way accessors are implemented, it is set for both the getter 7805// and setter on the first call to DefineAccessor and ignored on 7806// subsequent calls. 7807static Object* Runtime_DefineAccessor(Arguments args) { 7808 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); 7809 // Compute attributes. 7810 PropertyAttributes attributes = NONE; 7811 if (args.length() == 5) { 7812 CONVERT_CHECKED(Smi, attrs, args[4]); 7813 int value = attrs->value(); 7814 // Only attribute bits should be set. 7815 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 7816 attributes = static_cast<PropertyAttributes>(value); 7817 } 7818 7819 CONVERT_CHECKED(JSObject, obj, args[0]); 7820 CONVERT_CHECKED(String, name, args[1]); 7821 CONVERT_CHECKED(Smi, flag, args[2]); 7822 CONVERT_CHECKED(JSFunction, fun, args[3]); 7823 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes); 7824} 7825 7826 7827static Object* Runtime_LookupAccessor(Arguments args) { 7828 ASSERT(args.length() == 3); 7829 CONVERT_CHECKED(JSObject, obj, args[0]); 7830 CONVERT_CHECKED(String, name, args[1]); 7831 CONVERT_CHECKED(Smi, flag, args[2]); 7832 return obj->LookupAccessor(name, flag->value() == 0); 7833} 7834 7835 7836#ifdef ENABLE_DEBUGGER_SUPPORT 7837static Object* Runtime_DebugBreak(Arguments args) { 7838 ASSERT(args.length() == 0); 7839 return Execution::DebugBreakHelper(); 7840} 7841 7842 7843// Helper functions for wrapping and unwrapping stack frame ids. 7844static Smi* WrapFrameId(StackFrame::Id id) { 7845 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); 7846 return Smi::FromInt(id >> 2); 7847} 7848 7849 7850static StackFrame::Id UnwrapFrameId(Smi* wrapped) { 7851 return static_cast<StackFrame::Id>(wrapped->value() << 2); 7852} 7853 7854 7855// Adds a JavaScript function as a debug event listener. 7856// args[0]: debug event listener function to set or null or undefined for 7857// clearing the event listener function 7858// args[1]: object supplied during callback 7859static Object* Runtime_SetDebugEventListener(Arguments args) { 7860 ASSERT(args.length() == 2); 7861 RUNTIME_ASSERT(args[0]->IsJSFunction() || 7862 args[0]->IsUndefined() || 7863 args[0]->IsNull()); 7864 Handle<Object> callback = args.at<Object>(0); 7865 Handle<Object> data = args.at<Object>(1); 7866 Debugger::SetEventListener(callback, data); 7867 7868 return Heap::undefined_value(); 7869} 7870 7871 7872static Object* Runtime_Break(Arguments args) { 7873 ASSERT(args.length() == 0); 7874 StackGuard::DebugBreak(); 7875 return Heap::undefined_value(); 7876} 7877 7878 7879static Object* DebugLookupResultValue(Object* receiver, String* name, 7880 LookupResult* result, 7881 bool* caught_exception) { 7882 Object* value; 7883 switch (result->type()) { 7884 case NORMAL: 7885 value = result->holder()->GetNormalizedProperty(result); 7886 if (value->IsTheHole()) { 7887 return Heap::undefined_value(); 7888 } 7889 return value; 7890 case FIELD: 7891 value = 7892 JSObject::cast( 7893 result->holder())->FastPropertyAt(result->GetFieldIndex()); 7894 if (value->IsTheHole()) { 7895 return Heap::undefined_value(); 7896 } 7897 return value; 7898 case CONSTANT_FUNCTION: 7899 return result->GetConstantFunction(); 7900 case CALLBACKS: { 7901 Object* structure = result->GetCallbackObject(); 7902 if (structure->IsProxy() || structure->IsAccessorInfo()) { 7903 value = receiver->GetPropertyWithCallback( 7904 receiver, structure, name, result->holder()); 7905 if (value->IsException()) { 7906 value = Top::pending_exception(); 7907 Top::clear_pending_exception(); 7908 if (caught_exception != NULL) { 7909 *caught_exception = true; 7910 } 7911 } 7912 return value; 7913 } else { 7914 return Heap::undefined_value(); 7915 } 7916 } 7917 case INTERCEPTOR: 7918 case MAP_TRANSITION: 7919 case CONSTANT_TRANSITION: 7920 case NULL_DESCRIPTOR: 7921 return Heap::undefined_value(); 7922 default: 7923 UNREACHABLE(); 7924 } 7925 UNREACHABLE(); 7926 return Heap::undefined_value(); 7927} 7928 7929 7930// Get debugger related details for an object property. 7931// args[0]: object holding property 7932// args[1]: name of the property 7933// 7934// The array returned contains the following information: 7935// 0: Property value 7936// 1: Property details 7937// 2: Property value is exception 7938// 3: Getter function if defined 7939// 4: Setter function if defined 7940// Items 2-4 are only filled if the property has either a getter or a setter 7941// defined through __defineGetter__ and/or __defineSetter__. 7942static Object* Runtime_DebugGetPropertyDetails(Arguments args) { 7943 HandleScope scope; 7944 7945 ASSERT(args.length() == 2); 7946 7947 CONVERT_ARG_CHECKED(JSObject, obj, 0); 7948 CONVERT_ARG_CHECKED(String, name, 1); 7949 7950 // Make sure to set the current context to the context before the debugger was 7951 // entered (if the debugger is entered). The reason for switching context here 7952 // is that for some property lookups (accessors and interceptors) callbacks 7953 // into the embedding application can occour, and the embedding application 7954 // could have the assumption that its own global context is the current 7955 // context and not some internal debugger context. 7956 SaveContext save; 7957 if (Debug::InDebugger()) { 7958 Top::set_context(*Debug::debugger_entry()->GetContext()); 7959 } 7960 7961 // Skip the global proxy as it has no properties and always delegates to the 7962 // real global object. 7963 if (obj->IsJSGlobalProxy()) { 7964 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 7965 } 7966 7967 7968 // Check if the name is trivially convertible to an index and get the element 7969 // if so. 7970 uint32_t index; 7971 if (name->AsArrayIndex(&index)) { 7972 Handle<FixedArray> details = Factory::NewFixedArray(2); 7973 details->set(0, Runtime::GetElementOrCharAt(obj, index)); 7974 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi()); 7975 return *Factory::NewJSArrayWithElements(details); 7976 } 7977 7978 // Find the number of objects making up this. 7979 int length = LocalPrototypeChainLength(*obj); 7980 7981 // Try local lookup on each of the objects. 7982 Handle<JSObject> jsproto = obj; 7983 for (int i = 0; i < length; i++) { 7984 LookupResult result; 7985 jsproto->LocalLookup(*name, &result); 7986 if (result.IsProperty()) { 7987 // LookupResult is not GC safe as it holds raw object pointers. 7988 // GC can happen later in this code so put the required fields into 7989 // local variables using handles when required for later use. 7990 PropertyType result_type = result.type(); 7991 Handle<Object> result_callback_obj; 7992 if (result_type == CALLBACKS) { 7993 result_callback_obj = Handle<Object>(result.GetCallbackObject()); 7994 } 7995 Smi* property_details = result.GetPropertyDetails().AsSmi(); 7996 // DebugLookupResultValue can cause GC so details from LookupResult needs 7997 // to be copied to handles before this. 7998 bool caught_exception = false; 7999 Object* raw_value = DebugLookupResultValue(*obj, *name, &result, 8000 &caught_exception); 8001 if (raw_value->IsFailure()) return raw_value; 8002 Handle<Object> value(raw_value); 8003 8004 // If the callback object is a fixed array then it contains JavaScript 8005 // getter and/or setter. 8006 bool hasJavaScriptAccessors = result_type == CALLBACKS && 8007 result_callback_obj->IsFixedArray(); 8008 Handle<FixedArray> details = 8009 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2); 8010 details->set(0, *value); 8011 details->set(1, property_details); 8012 if (hasJavaScriptAccessors) { 8013 details->set(2, 8014 caught_exception ? Heap::true_value() 8015 : Heap::false_value()); 8016 details->set(3, FixedArray::cast(*result_callback_obj)->get(0)); 8017 details->set(4, FixedArray::cast(*result_callback_obj)->get(1)); 8018 } 8019 8020 return *Factory::NewJSArrayWithElements(details); 8021 } 8022 if (i < length - 1) { 8023 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 8024 } 8025 } 8026 8027 return Heap::undefined_value(); 8028} 8029 8030 8031static Object* Runtime_DebugGetProperty(Arguments args) { 8032 HandleScope scope; 8033 8034 ASSERT(args.length() == 2); 8035 8036 CONVERT_ARG_CHECKED(JSObject, obj, 0); 8037 CONVERT_ARG_CHECKED(String, name, 1); 8038 8039 LookupResult result; 8040 obj->Lookup(*name, &result); 8041 if (result.IsProperty()) { 8042 return DebugLookupResultValue(*obj, *name, &result, NULL); 8043 } 8044 return Heap::undefined_value(); 8045} 8046 8047 8048// Return the property type calculated from the property details. 8049// args[0]: smi with property details. 8050static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) { 8051 ASSERT(args.length() == 1); 8052 CONVERT_CHECKED(Smi, details, args[0]); 8053 PropertyType type = PropertyDetails(details).type(); 8054 return Smi::FromInt(static_cast<int>(type)); 8055} 8056 8057 8058// Return the property attribute calculated from the property details. 8059// args[0]: smi with property details. 8060static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) { 8061 ASSERT(args.length() == 1); 8062 CONVERT_CHECKED(Smi, details, args[0]); 8063 PropertyAttributes attributes = PropertyDetails(details).attributes(); 8064 return Smi::FromInt(static_cast<int>(attributes)); 8065} 8066 8067 8068// Return the property insertion index calculated from the property details. 8069// args[0]: smi with property details. 8070static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) { 8071 ASSERT(args.length() == 1); 8072 CONVERT_CHECKED(Smi, details, args[0]); 8073 int index = PropertyDetails(details).index(); 8074 return Smi::FromInt(index); 8075} 8076 8077 8078// Return property value from named interceptor. 8079// args[0]: object 8080// args[1]: property name 8081static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) { 8082 HandleScope scope; 8083 ASSERT(args.length() == 2); 8084 CONVERT_ARG_CHECKED(JSObject, obj, 0); 8085 RUNTIME_ASSERT(obj->HasNamedInterceptor()); 8086 CONVERT_ARG_CHECKED(String, name, 1); 8087 8088 PropertyAttributes attributes; 8089 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes); 8090} 8091 8092 8093// Return element value from indexed interceptor. 8094// args[0]: object 8095// args[1]: index 8096static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) { 8097 HandleScope scope; 8098 ASSERT(args.length() == 2); 8099 CONVERT_ARG_CHECKED(JSObject, obj, 0); 8100 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); 8101 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); 8102 8103 return obj->GetElementWithInterceptor(*obj, index); 8104} 8105 8106 8107static Object* Runtime_CheckExecutionState(Arguments args) { 8108 ASSERT(args.length() >= 1); 8109 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 8110 // Check that the break id is valid. 8111 if (Debug::break_id() == 0 || break_id != Debug::break_id()) { 8112 return Top::Throw(Heap::illegal_execution_state_symbol()); 8113 } 8114 8115 return Heap::true_value(); 8116} 8117 8118 8119static Object* Runtime_GetFrameCount(Arguments args) { 8120 HandleScope scope; 8121 ASSERT(args.length() == 1); 8122 8123 // Check arguments. 8124 Object* result = Runtime_CheckExecutionState(args); 8125 if (result->IsFailure()) return result; 8126 8127 // Count all frames which are relevant to debugging stack trace. 8128 int n = 0; 8129 StackFrame::Id id = Debug::break_frame_id(); 8130 if (id == StackFrame::NO_ID) { 8131 // If there is no JavaScript stack frame count is 0. 8132 return Smi::FromInt(0); 8133 } 8134 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++; 8135 return Smi::FromInt(n); 8136} 8137 8138 8139static const int kFrameDetailsFrameIdIndex = 0; 8140static const int kFrameDetailsReceiverIndex = 1; 8141static const int kFrameDetailsFunctionIndex = 2; 8142static const int kFrameDetailsArgumentCountIndex = 3; 8143static const int kFrameDetailsLocalCountIndex = 4; 8144static const int kFrameDetailsSourcePositionIndex = 5; 8145static const int kFrameDetailsConstructCallIndex = 6; 8146static const int kFrameDetailsDebuggerFrameIndex = 7; 8147static const int kFrameDetailsFirstDynamicIndex = 8; 8148 8149// Return an array with frame details 8150// args[0]: number: break id 8151// args[1]: number: frame index 8152// 8153// The array returned contains the following information: 8154// 0: Frame id 8155// 1: Receiver 8156// 2: Function 8157// 3: Argument count 8158// 4: Local count 8159// 5: Source position 8160// 6: Constructor call 8161// 7: Debugger frame 8162// Arguments name, value 8163// Locals name, value 8164static Object* Runtime_GetFrameDetails(Arguments args) { 8165 HandleScope scope; 8166 ASSERT(args.length() == 2); 8167 8168 // Check arguments. 8169 Object* check = Runtime_CheckExecutionState(args); 8170 if (check->IsFailure()) return check; 8171 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 8172 8173 // Find the relevant frame with the requested index. 8174 StackFrame::Id id = Debug::break_frame_id(); 8175 if (id == StackFrame::NO_ID) { 8176 // If there are no JavaScript stack frames return undefined. 8177 return Heap::undefined_value(); 8178 } 8179 int count = 0; 8180 JavaScriptFrameIterator it(id); 8181 for (; !it.done(); it.Advance()) { 8182 if (count == index) break; 8183 count++; 8184 } 8185 if (it.done()) return Heap::undefined_value(); 8186 8187 // Traverse the saved contexts chain to find the active context for the 8188 // selected frame. 8189 SaveContext* save = Top::save_context(); 8190 while (save != NULL && !save->below(it.frame())) { 8191 save = save->prev(); 8192 } 8193 ASSERT(save != NULL); 8194 8195 // Get the frame id. 8196 Handle<Object> frame_id(WrapFrameId(it.frame()->id())); 8197 8198 // Find source position. 8199 int position = it.frame()->code()->SourcePosition(it.frame()->pc()); 8200 8201 // Check for constructor frame. 8202 bool constructor = it.frame()->IsConstructor(); 8203 8204 // Get code and read scope info from it for local variable information. 8205 Handle<Code> code(it.frame()->code()); 8206 ScopeInfo<> info(*code); 8207 8208 // Get the context. 8209 Handle<Context> context(Context::cast(it.frame()->context())); 8210 8211 // Get the locals names and values into a temporary array. 8212 // 8213 // TODO(1240907): Hide compiler-introduced stack variables 8214 // (e.g. .result)? For users of the debugger, they will probably be 8215 // confusing. 8216 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2); 8217 for (int i = 0; i < info.NumberOfLocals(); i++) { 8218 // Name of the local. 8219 locals->set(i * 2, *info.LocalName(i)); 8220 8221 // Fetch the value of the local - either from the stack or from a 8222 // heap-allocated context. 8223 if (i < info.number_of_stack_slots()) { 8224 locals->set(i * 2 + 1, it.frame()->GetExpression(i)); 8225 } else { 8226 Handle<String> name = info.LocalName(i); 8227 // Traverse the context chain to the function context as all local 8228 // variables stored in the context will be on the function context. 8229 while (!context->is_function_context()) { 8230 context = Handle<Context>(context->previous()); 8231 } 8232 ASSERT(context->is_function_context()); 8233 locals->set(i * 2 + 1, 8234 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name, 8235 NULL))); 8236 } 8237 } 8238 8239 // Now advance to the arguments adapter frame (if any). If contains all 8240 // the provided parameters and 8241 8242 // Now advance to the arguments adapter frame (if any). It contains all 8243 // the provided parameters whereas the function frame always have the number 8244 // of arguments matching the functions parameters. The rest of the 8245 // information (except for what is collected above) is the same. 8246 it.AdvanceToArgumentsFrame(); 8247 8248 // Find the number of arguments to fill. At least fill the number of 8249 // parameters for the function and fill more if more parameters are provided. 8250 int argument_count = info.number_of_parameters(); 8251 if (argument_count < it.frame()->GetProvidedParametersCount()) { 8252 argument_count = it.frame()->GetProvidedParametersCount(); 8253 } 8254 8255 // Calculate the size of the result. 8256 int details_size = kFrameDetailsFirstDynamicIndex + 8257 2 * (argument_count + info.NumberOfLocals()); 8258 Handle<FixedArray> details = Factory::NewFixedArray(details_size); 8259 8260 // Add the frame id. 8261 details->set(kFrameDetailsFrameIdIndex, *frame_id); 8262 8263 // Add the function (same as in function frame). 8264 details->set(kFrameDetailsFunctionIndex, it.frame()->function()); 8265 8266 // Add the arguments count. 8267 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); 8268 8269 // Add the locals count 8270 details->set(kFrameDetailsLocalCountIndex, 8271 Smi::FromInt(info.NumberOfLocals())); 8272 8273 // Add the source position. 8274 if (position != RelocInfo::kNoPosition) { 8275 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 8276 } else { 8277 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value()); 8278 } 8279 8280 // Add the constructor information. 8281 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor)); 8282 8283 // Add information on whether this frame is invoked in the debugger context. 8284 details->set(kFrameDetailsDebuggerFrameIndex, 8285 Heap::ToBoolean(*save->context() == *Debug::debug_context())); 8286 8287 // Fill the dynamic part. 8288 int details_index = kFrameDetailsFirstDynamicIndex; 8289 8290 // Add arguments name and value. 8291 for (int i = 0; i < argument_count; i++) { 8292 // Name of the argument. 8293 if (i < info.number_of_parameters()) { 8294 details->set(details_index++, *info.parameter_name(i)); 8295 } else { 8296 details->set(details_index++, Heap::undefined_value()); 8297 } 8298 8299 // Parameter value. 8300 if (i < it.frame()->GetProvidedParametersCount()) { 8301 details->set(details_index++, it.frame()->GetParameter(i)); 8302 } else { 8303 details->set(details_index++, Heap::undefined_value()); 8304 } 8305 } 8306 8307 // Add locals name and value from the temporary copy from the function frame. 8308 for (int i = 0; i < info.NumberOfLocals() * 2; i++) { 8309 details->set(details_index++, locals->get(i)); 8310 } 8311 8312 // Add the receiver (same as in function frame). 8313 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE 8314 // THE FRAME ITERATOR TO WRAP THE RECEIVER. 8315 Handle<Object> receiver(it.frame()->receiver()); 8316 if (!receiver->IsJSObject()) { 8317 // If the receiver is NOT a JSObject we have hit an optimization 8318 // where a value object is not converted into a wrapped JS objects. 8319 // To hide this optimization from the debugger, we wrap the receiver 8320 // by creating correct wrapper object based on the calling frame's 8321 // global context. 8322 it.Advance(); 8323 Handle<Context> calling_frames_global_context( 8324 Context::cast(Context::cast(it.frame()->context())->global_context())); 8325 receiver = Factory::ToObject(receiver, calling_frames_global_context); 8326 } 8327 details->set(kFrameDetailsReceiverIndex, *receiver); 8328 8329 ASSERT_EQ(details_size, details_index); 8330 return *Factory::NewJSArrayWithElements(details); 8331} 8332 8333 8334// Copy all the context locals into an object used to materialize a scope. 8335static void CopyContextLocalsToScopeObject(Handle<Code> code, 8336 ScopeInfo<>& scope_info, 8337 Handle<Context> context, 8338 Handle<JSObject> scope_object) { 8339 // Fill all context locals to the context extension. 8340 for (int i = Context::MIN_CONTEXT_SLOTS; 8341 i < scope_info.number_of_context_slots(); 8342 i++) { 8343 int context_index = 8344 ScopeInfo<>::ContextSlotIndex(*code, 8345 *scope_info.context_slot_name(i), 8346 NULL); 8347 8348 // Don't include the arguments shadow (.arguments) context variable. 8349 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) { 8350 SetProperty(scope_object, 8351 scope_info.context_slot_name(i), 8352 Handle<Object>(context->get(context_index)), NONE); 8353 } 8354 } 8355} 8356 8357 8358// Create a plain JSObject which materializes the local scope for the specified 8359// frame. 8360static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) { 8361 Handle<JSFunction> function(JSFunction::cast(frame->function())); 8362 Handle<Code> code(function->code()); 8363 ScopeInfo<> scope_info(*code); 8364 8365 // Allocate and initialize a JSObject with all the arguments, stack locals 8366 // heap locals and extension properties of the debugged function. 8367 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function()); 8368 8369 // First fill all parameters. 8370 for (int i = 0; i < scope_info.number_of_parameters(); ++i) { 8371 SetProperty(local_scope, 8372 scope_info.parameter_name(i), 8373 Handle<Object>(frame->GetParameter(i)), NONE); 8374 } 8375 8376 // Second fill all stack locals. 8377 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) { 8378 SetProperty(local_scope, 8379 scope_info.stack_slot_name(i), 8380 Handle<Object>(frame->GetExpression(i)), NONE); 8381 } 8382 8383 // Third fill all context locals. 8384 Handle<Context> frame_context(Context::cast(frame->context())); 8385 Handle<Context> function_context(frame_context->fcontext()); 8386 CopyContextLocalsToScopeObject(code, scope_info, 8387 function_context, local_scope); 8388 8389 // Finally copy any properties from the function context extension. This will 8390 // be variables introduced by eval. 8391 if (function_context->closure() == *function) { 8392 if (function_context->has_extension() && 8393 !function_context->IsGlobalContext()) { 8394 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 8395 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); 8396 for (int i = 0; i < keys->length(); i++) { 8397 // Names of variables introduced by eval are strings. 8398 ASSERT(keys->get(i)->IsString()); 8399 Handle<String> key(String::cast(keys->get(i))); 8400 SetProperty(local_scope, key, GetProperty(ext, key), NONE); 8401 } 8402 } 8403 } 8404 return local_scope; 8405} 8406 8407 8408// Create a plain JSObject which materializes the closure content for the 8409// context. 8410static Handle<JSObject> MaterializeClosure(Handle<Context> context) { 8411 ASSERT(context->is_function_context()); 8412 8413 Handle<Code> code(context->closure()->code()); 8414 ScopeInfo<> scope_info(*code); 8415 8416 // Allocate and initialize a JSObject with all the content of theis function 8417 // closure. 8418 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function()); 8419 8420 // Check whether the arguments shadow object exists. 8421 int arguments_shadow_index = 8422 ScopeInfo<>::ContextSlotIndex(*code, 8423 Heap::arguments_shadow_symbol(), 8424 NULL); 8425 if (arguments_shadow_index >= 0) { 8426 // In this case all the arguments are available in the arguments shadow 8427 // object. 8428 Handle<JSObject> arguments_shadow( 8429 JSObject::cast(context->get(arguments_shadow_index))); 8430 for (int i = 0; i < scope_info.number_of_parameters(); ++i) { 8431 SetProperty(closure_scope, 8432 scope_info.parameter_name(i), 8433 Handle<Object>(arguments_shadow->GetElement(i)), NONE); 8434 } 8435 } 8436 8437 // Fill all context locals to the context extension. 8438 CopyContextLocalsToScopeObject(code, scope_info, context, closure_scope); 8439 8440 // Finally copy any properties from the function context extension. This will 8441 // be variables introduced by eval. 8442 if (context->has_extension()) { 8443 Handle<JSObject> ext(JSObject::cast(context->extension())); 8444 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); 8445 for (int i = 0; i < keys->length(); i++) { 8446 // Names of variables introduced by eval are strings. 8447 ASSERT(keys->get(i)->IsString()); 8448 Handle<String> key(String::cast(keys->get(i))); 8449 SetProperty(closure_scope, key, GetProperty(ext, key), NONE); 8450 } 8451 } 8452 8453 return closure_scope; 8454} 8455 8456 8457// Iterate over the actual scopes visible from a stack frame. All scopes are 8458// backed by an actual context except the local scope, which is inserted 8459// "artifically" in the context chain. 8460class ScopeIterator { 8461 public: 8462 enum ScopeType { 8463 ScopeTypeGlobal = 0, 8464 ScopeTypeLocal, 8465 ScopeTypeWith, 8466 ScopeTypeClosure, 8467 // Every catch block contains an implicit with block (its parameter is 8468 // a JSContextExtensionObject) that extends current scope with a variable 8469 // holding exception object. Such with blocks are treated as scopes of their 8470 // own type. 8471 ScopeTypeCatch 8472 }; 8473 8474 explicit ScopeIterator(JavaScriptFrame* frame) 8475 : frame_(frame), 8476 function_(JSFunction::cast(frame->function())), 8477 context_(Context::cast(frame->context())), 8478 local_done_(false), 8479 at_local_(false) { 8480 8481 // Check whether the first scope is actually a local scope. 8482 if (context_->IsGlobalContext()) { 8483 // If there is a stack slot for .result then this local scope has been 8484 // created for evaluating top level code and it is not a real local scope. 8485 // Checking for the existence of .result seems fragile, but the scope info 8486 // saved with the code object does not otherwise have that information. 8487 Handle<Code> code(function_->code()); 8488 int index = ScopeInfo<>::StackSlotIndex(*code, Heap::result_symbol()); 8489 at_local_ = index < 0; 8490 } else if (context_->is_function_context()) { 8491 at_local_ = true; 8492 } 8493 } 8494 8495 // More scopes? 8496 bool Done() { return context_.is_null(); } 8497 8498 // Move to the next scope. 8499 void Next() { 8500 // If at a local scope mark the local scope as passed. 8501 if (at_local_) { 8502 at_local_ = false; 8503 local_done_ = true; 8504 8505 // If the current context is not associated with the local scope the 8506 // current context is the next real scope, so don't move to the next 8507 // context in this case. 8508 if (context_->closure() != *function_) { 8509 return; 8510 } 8511 } 8512 8513 // The global scope is always the last in the chain. 8514 if (context_->IsGlobalContext()) { 8515 context_ = Handle<Context>(); 8516 return; 8517 } 8518 8519 // Move to the next context. 8520 if (context_->is_function_context()) { 8521 context_ = Handle<Context>(Context::cast(context_->closure()->context())); 8522 } else { 8523 context_ = Handle<Context>(context_->previous()); 8524 } 8525 8526 // If passing the local scope indicate that the current scope is now the 8527 // local scope. 8528 if (!local_done_ && 8529 (context_->IsGlobalContext() || (context_->is_function_context()))) { 8530 at_local_ = true; 8531 } 8532 } 8533 8534 // Return the type of the current scope. 8535 int Type() { 8536 if (at_local_) { 8537 return ScopeTypeLocal; 8538 } 8539 if (context_->IsGlobalContext()) { 8540 ASSERT(context_->global()->IsGlobalObject()); 8541 return ScopeTypeGlobal; 8542 } 8543 if (context_->is_function_context()) { 8544 return ScopeTypeClosure; 8545 } 8546 ASSERT(context_->has_extension()); 8547 // Current scope is either an explicit with statement or a with statement 8548 // implicitely generated for a catch block. 8549 // If the extension object here is a JSContextExtensionObject then 8550 // current with statement is one frome a catch block otherwise it's a 8551 // regular with statement. 8552 if (context_->extension()->IsJSContextExtensionObject()) { 8553 return ScopeTypeCatch; 8554 } 8555 return ScopeTypeWith; 8556 } 8557 8558 // Return the JavaScript object with the content of the current scope. 8559 Handle<JSObject> ScopeObject() { 8560 switch (Type()) { 8561 case ScopeIterator::ScopeTypeGlobal: 8562 return Handle<JSObject>(CurrentContext()->global()); 8563 break; 8564 case ScopeIterator::ScopeTypeLocal: 8565 // Materialize the content of the local scope into a JSObject. 8566 return MaterializeLocalScope(frame_); 8567 break; 8568 case ScopeIterator::ScopeTypeWith: 8569 case ScopeIterator::ScopeTypeCatch: 8570 // Return the with object. 8571 return Handle<JSObject>(CurrentContext()->extension()); 8572 break; 8573 case ScopeIterator::ScopeTypeClosure: 8574 // Materialize the content of the closure scope into a JSObject. 8575 return MaterializeClosure(CurrentContext()); 8576 break; 8577 } 8578 UNREACHABLE(); 8579 return Handle<JSObject>(); 8580 } 8581 8582 // Return the context for this scope. For the local context there might not 8583 // be an actual context. 8584 Handle<Context> CurrentContext() { 8585 if (at_local_ && context_->closure() != *function_) { 8586 return Handle<Context>(); 8587 } 8588 return context_; 8589 } 8590 8591#ifdef DEBUG 8592 // Debug print of the content of the current scope. 8593 void DebugPrint() { 8594 switch (Type()) { 8595 case ScopeIterator::ScopeTypeGlobal: 8596 PrintF("Global:\n"); 8597 CurrentContext()->Print(); 8598 break; 8599 8600 case ScopeIterator::ScopeTypeLocal: { 8601 PrintF("Local:\n"); 8602 Handle<Code> code(function_->code()); 8603 ScopeInfo<> scope_info(*code); 8604 scope_info.Print(); 8605 if (!CurrentContext().is_null()) { 8606 CurrentContext()->Print(); 8607 if (CurrentContext()->has_extension()) { 8608 Handle<JSObject> extension = 8609 Handle<JSObject>(CurrentContext()->extension()); 8610 if (extension->IsJSContextExtensionObject()) { 8611 extension->Print(); 8612 } 8613 } 8614 } 8615 break; 8616 } 8617 8618 case ScopeIterator::ScopeTypeWith: { 8619 PrintF("With:\n"); 8620 Handle<JSObject> extension = 8621 Handle<JSObject>(CurrentContext()->extension()); 8622 extension->Print(); 8623 break; 8624 } 8625 8626 case ScopeIterator::ScopeTypeCatch: { 8627 PrintF("Catch:\n"); 8628 Handle<JSObject> extension = 8629 Handle<JSObject>(CurrentContext()->extension()); 8630 extension->Print(); 8631 break; 8632 } 8633 8634 case ScopeIterator::ScopeTypeClosure: { 8635 PrintF("Closure:\n"); 8636 CurrentContext()->Print(); 8637 if (CurrentContext()->has_extension()) { 8638 Handle<JSObject> extension = 8639 Handle<JSObject>(CurrentContext()->extension()); 8640 if (extension->IsJSContextExtensionObject()) { 8641 extension->Print(); 8642 } 8643 } 8644 break; 8645 } 8646 8647 default: 8648 UNREACHABLE(); 8649 } 8650 PrintF("\n"); 8651 } 8652#endif 8653 8654 private: 8655 JavaScriptFrame* frame_; 8656 Handle<JSFunction> function_; 8657 Handle<Context> context_; 8658 bool local_done_; 8659 bool at_local_; 8660 8661 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); 8662}; 8663 8664 8665static Object* Runtime_GetScopeCount(Arguments args) { 8666 HandleScope scope; 8667 ASSERT(args.length() == 2); 8668 8669 // Check arguments. 8670 Object* check = Runtime_CheckExecutionState(args); 8671 if (check->IsFailure()) return check; 8672 CONVERT_CHECKED(Smi, wrapped_id, args[1]); 8673 8674 // Get the frame where the debugging is performed. 8675 StackFrame::Id id = UnwrapFrameId(wrapped_id); 8676 JavaScriptFrameIterator it(id); 8677 JavaScriptFrame* frame = it.frame(); 8678 8679 // Count the visible scopes. 8680 int n = 0; 8681 for (ScopeIterator it(frame); !it.Done(); it.Next()) { 8682 n++; 8683 } 8684 8685 return Smi::FromInt(n); 8686} 8687 8688 8689static const int kScopeDetailsTypeIndex = 0; 8690static const int kScopeDetailsObjectIndex = 1; 8691static const int kScopeDetailsSize = 2; 8692 8693// Return an array with scope details 8694// args[0]: number: break id 8695// args[1]: number: frame index 8696// args[2]: number: scope index 8697// 8698// The array returned contains the following information: 8699// 0: Scope type 8700// 1: Scope object 8701static Object* Runtime_GetScopeDetails(Arguments args) { 8702 HandleScope scope; 8703 ASSERT(args.length() == 3); 8704 8705 // Check arguments. 8706 Object* check = Runtime_CheckExecutionState(args); 8707 if (check->IsFailure()) return check; 8708 CONVERT_CHECKED(Smi, wrapped_id, args[1]); 8709 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]); 8710 8711 // Get the frame where the debugging is performed. 8712 StackFrame::Id id = UnwrapFrameId(wrapped_id); 8713 JavaScriptFrameIterator frame_it(id); 8714 JavaScriptFrame* frame = frame_it.frame(); 8715 8716 // Find the requested scope. 8717 int n = 0; 8718 ScopeIterator it(frame); 8719 for (; !it.Done() && n < index; it.Next()) { 8720 n++; 8721 } 8722 if (it.Done()) { 8723 return Heap::undefined_value(); 8724 } 8725 8726 // Calculate the size of the result. 8727 int details_size = kScopeDetailsSize; 8728 Handle<FixedArray> details = Factory::NewFixedArray(details_size); 8729 8730 // Fill in scope details. 8731 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type())); 8732 details->set(kScopeDetailsObjectIndex, *it.ScopeObject()); 8733 8734 return *Factory::NewJSArrayWithElements(details); 8735} 8736 8737 8738static Object* Runtime_DebugPrintScopes(Arguments args) { 8739 HandleScope scope; 8740 ASSERT(args.length() == 0); 8741 8742#ifdef DEBUG 8743 // Print the scopes for the top frame. 8744 StackFrameLocator locator; 8745 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 8746 for (ScopeIterator it(frame); !it.Done(); it.Next()) { 8747 it.DebugPrint(); 8748 } 8749#endif 8750 return Heap::undefined_value(); 8751} 8752 8753 8754static Object* Runtime_GetCFrames(Arguments args) { 8755 HandleScope scope; 8756 ASSERT(args.length() == 1); 8757 Object* result = Runtime_CheckExecutionState(args); 8758 if (result->IsFailure()) return result; 8759 8760#if V8_HOST_ARCH_64_BIT 8761 UNIMPLEMENTED(); 8762 return Heap::undefined_value(); 8763#else 8764 8765 static const int kMaxCFramesSize = 200; 8766 ScopedVector<OS::StackFrame> frames(kMaxCFramesSize); 8767 int frames_count = OS::StackWalk(frames); 8768 if (frames_count == OS::kStackWalkError) { 8769 return Heap::undefined_value(); 8770 } 8771 8772 Handle<String> address_str = Factory::LookupAsciiSymbol("address"); 8773 Handle<String> text_str = Factory::LookupAsciiSymbol("text"); 8774 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count); 8775 for (int i = 0; i < frames_count; i++) { 8776 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function()); 8777 frame_value->SetProperty( 8778 *address_str, 8779 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)), 8780 NONE); 8781 8782 // Get the stack walk text for this frame. 8783 Handle<String> frame_text; 8784 int frame_text_length = StrLength(frames[i].text); 8785 if (frame_text_length > 0) { 8786 Vector<const char> str(frames[i].text, frame_text_length); 8787 frame_text = Factory::NewStringFromAscii(str); 8788 } 8789 8790 if (!frame_text.is_null()) { 8791 frame_value->SetProperty(*text_str, *frame_text, NONE); 8792 } 8793 8794 frames_array->set(i, *frame_value); 8795 } 8796 return *Factory::NewJSArrayWithElements(frames_array); 8797#endif // V8_HOST_ARCH_64_BIT 8798} 8799 8800 8801static Object* Runtime_GetThreadCount(Arguments args) { 8802 HandleScope scope; 8803 ASSERT(args.length() == 1); 8804 8805 // Check arguments. 8806 Object* result = Runtime_CheckExecutionState(args); 8807 if (result->IsFailure()) return result; 8808 8809 // Count all archived V8 threads. 8810 int n = 0; 8811 for (ThreadState* thread = ThreadState::FirstInUse(); 8812 thread != NULL; 8813 thread = thread->Next()) { 8814 n++; 8815 } 8816 8817 // Total number of threads is current thread and archived threads. 8818 return Smi::FromInt(n + 1); 8819} 8820 8821 8822static const int kThreadDetailsCurrentThreadIndex = 0; 8823static const int kThreadDetailsThreadIdIndex = 1; 8824static const int kThreadDetailsSize = 2; 8825 8826// Return an array with thread details 8827// args[0]: number: break id 8828// args[1]: number: thread index 8829// 8830// The array returned contains the following information: 8831// 0: Is current thread? 8832// 1: Thread id 8833static Object* Runtime_GetThreadDetails(Arguments args) { 8834 HandleScope scope; 8835 ASSERT(args.length() == 2); 8836 8837 // Check arguments. 8838 Object* check = Runtime_CheckExecutionState(args); 8839 if (check->IsFailure()) return check; 8840 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 8841 8842 // Allocate array for result. 8843 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize); 8844 8845 // Thread index 0 is current thread. 8846 if (index == 0) { 8847 // Fill the details. 8848 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value()); 8849 details->set(kThreadDetailsThreadIdIndex, 8850 Smi::FromInt(ThreadManager::CurrentId())); 8851 } else { 8852 // Find the thread with the requested index. 8853 int n = 1; 8854 ThreadState* thread = ThreadState::FirstInUse(); 8855 while (index != n && thread != NULL) { 8856 thread = thread->Next(); 8857 n++; 8858 } 8859 if (thread == NULL) { 8860 return Heap::undefined_value(); 8861 } 8862 8863 // Fill the details. 8864 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value()); 8865 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id())); 8866 } 8867 8868 // Convert to JS array and return. 8869 return *Factory::NewJSArrayWithElements(details); 8870} 8871 8872 8873static Object* Runtime_GetBreakLocations(Arguments args) { 8874 HandleScope scope; 8875 ASSERT(args.length() == 1); 8876 8877 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 8878 Handle<SharedFunctionInfo> shared(fun->shared()); 8879 // Find the number of break points 8880 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared); 8881 if (break_locations->IsUndefined()) return Heap::undefined_value(); 8882 // Return array as JS array 8883 return *Factory::NewJSArrayWithElements( 8884 Handle<FixedArray>::cast(break_locations)); 8885} 8886 8887 8888// Set a break point in a function 8889// args[0]: function 8890// args[1]: number: break source position (within the function source) 8891// args[2]: number: break point object 8892static Object* Runtime_SetFunctionBreakPoint(Arguments args) { 8893 HandleScope scope; 8894 ASSERT(args.length() == 3); 8895 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 8896 Handle<SharedFunctionInfo> shared(fun->shared()); 8897 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 8898 RUNTIME_ASSERT(source_position >= 0); 8899 Handle<Object> break_point_object_arg = args.at<Object>(2); 8900 8901 // Set break point. 8902 Debug::SetBreakPoint(shared, source_position, break_point_object_arg); 8903 8904 return Heap::undefined_value(); 8905} 8906 8907 8908Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script, 8909 int position) { 8910 // Iterate the heap looking for SharedFunctionInfo generated from the 8911 // script. The inner most SharedFunctionInfo containing the source position 8912 // for the requested break point is found. 8913 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo 8914 // which is found is not compiled it is compiled and the heap is iterated 8915 // again as the compilation might create inner functions from the newly 8916 // compiled function and the actual requested break point might be in one of 8917 // these functions. 8918 bool done = false; 8919 // The current candidate for the source position: 8920 int target_start_position = RelocInfo::kNoPosition; 8921 Handle<SharedFunctionInfo> target; 8922 // The current candidate for the last function in script: 8923 Handle<SharedFunctionInfo> last; 8924 while (!done) { 8925 HeapIterator iterator; 8926 for (HeapObject* obj = iterator.next(); 8927 obj != NULL; obj = iterator.next()) { 8928 if (obj->IsSharedFunctionInfo()) { 8929 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj)); 8930 if (shared->script() == *script) { 8931 // If the SharedFunctionInfo found has the requested script data and 8932 // contains the source position it is a candidate. 8933 int start_position = shared->function_token_position(); 8934 if (start_position == RelocInfo::kNoPosition) { 8935 start_position = shared->start_position(); 8936 } 8937 if (start_position <= position && 8938 position <= shared->end_position()) { 8939 // If there is no candidate or this function is within the current 8940 // candidate this is the new candidate. 8941 if (target.is_null()) { 8942 target_start_position = start_position; 8943 target = shared; 8944 } else { 8945 if (target_start_position == start_position && 8946 shared->end_position() == target->end_position()) { 8947 // If a top-level function contain only one function 8948 // declartion the source for the top-level and the function is 8949 // the same. In that case prefer the non top-level function. 8950 if (!shared->is_toplevel()) { 8951 target_start_position = start_position; 8952 target = shared; 8953 } 8954 } else if (target_start_position <= start_position && 8955 shared->end_position() <= target->end_position()) { 8956 // This containment check includes equality as a function inside 8957 // a top-level function can share either start or end position 8958 // with the top-level function. 8959 target_start_position = start_position; 8960 target = shared; 8961 } 8962 } 8963 } 8964 8965 // Keep track of the last function in the script. 8966 if (last.is_null() || 8967 shared->end_position() > last->start_position()) { 8968 last = shared; 8969 } 8970 } 8971 } 8972 } 8973 8974 // Make sure some candidate is selected. 8975 if (target.is_null()) { 8976 if (!last.is_null()) { 8977 // Position after the last function - use last. 8978 target = last; 8979 } else { 8980 // Unable to find function - possibly script without any function. 8981 return Heap::undefined_value(); 8982 } 8983 } 8984 8985 // If the candidate found is compiled we are done. NOTE: when lazy 8986 // compilation of inner functions is introduced some additional checking 8987 // needs to be done here to compile inner functions. 8988 done = target->is_compiled(); 8989 if (!done) { 8990 // If the candidate is not compiled compile it to reveal any inner 8991 // functions which might contain the requested source position. 8992 CompileLazyShared(target, KEEP_EXCEPTION); 8993 } 8994 } 8995 8996 return *target; 8997} 8998 8999 9000// Change the state of a break point in a script. NOTE: Regarding performance 9001// see the NOTE for GetScriptFromScriptData. 9002// args[0]: script to set break point in 9003// args[1]: number: break source position (within the script source) 9004// args[2]: number: break point object 9005static Object* Runtime_SetScriptBreakPoint(Arguments args) { 9006 HandleScope scope; 9007 ASSERT(args.length() == 3); 9008 CONVERT_ARG_CHECKED(JSValue, wrapper, 0); 9009 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 9010 RUNTIME_ASSERT(source_position >= 0); 9011 Handle<Object> break_point_object_arg = args.at<Object>(2); 9012 9013 // Get the script from the script wrapper. 9014 RUNTIME_ASSERT(wrapper->value()->IsScript()); 9015 Handle<Script> script(Script::cast(wrapper->value())); 9016 9017 Object* result = Runtime::FindSharedFunctionInfoInScript( 9018 script, source_position); 9019 if (!result->IsUndefined()) { 9020 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result)); 9021 // Find position within function. The script position might be before the 9022 // source position of the first function. 9023 int position; 9024 if (shared->start_position() > source_position) { 9025 position = 0; 9026 } else { 9027 position = source_position - shared->start_position(); 9028 } 9029 Debug::SetBreakPoint(shared, position, break_point_object_arg); 9030 } 9031 return Heap::undefined_value(); 9032} 9033 9034 9035// Clear a break point 9036// args[0]: number: break point object 9037static Object* Runtime_ClearBreakPoint(Arguments args) { 9038 HandleScope scope; 9039 ASSERT(args.length() == 1); 9040 Handle<Object> break_point_object_arg = args.at<Object>(0); 9041 9042 // Clear break point. 9043 Debug::ClearBreakPoint(break_point_object_arg); 9044 9045 return Heap::undefined_value(); 9046} 9047 9048 9049// Change the state of break on exceptions 9050// args[0]: boolean indicating uncaught exceptions 9051// args[1]: boolean indicating on/off 9052static Object* Runtime_ChangeBreakOnException(Arguments args) { 9053 HandleScope scope; 9054 ASSERT(args.length() == 2); 9055 ASSERT(args[0]->IsNumber()); 9056 ASSERT(args[1]->IsBoolean()); 9057 9058 // Update break point state 9059 ExceptionBreakType type = 9060 static_cast<ExceptionBreakType>(NumberToUint32(args[0])); 9061 bool enable = args[1]->ToBoolean()->IsTrue(); 9062 Debug::ChangeBreakOnException(type, enable); 9063 return Heap::undefined_value(); 9064} 9065 9066 9067// Prepare for stepping 9068// args[0]: break id for checking execution state 9069// args[1]: step action from the enumeration StepAction 9070// args[2]: number of times to perform the step, for step out it is the number 9071// of frames to step down. 9072static Object* Runtime_PrepareStep(Arguments args) { 9073 HandleScope scope; 9074 ASSERT(args.length() == 3); 9075 // Check arguments. 9076 Object* check = Runtime_CheckExecutionState(args); 9077 if (check->IsFailure()) return check; 9078 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { 9079 return Top::Throw(Heap::illegal_argument_symbol()); 9080 } 9081 9082 // Get the step action and check validity. 9083 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); 9084 if (step_action != StepIn && 9085 step_action != StepNext && 9086 step_action != StepOut && 9087 step_action != StepInMin && 9088 step_action != StepMin) { 9089 return Top::Throw(Heap::illegal_argument_symbol()); 9090 } 9091 9092 // Get the number of steps. 9093 int step_count = NumberToInt32(args[2]); 9094 if (step_count < 1) { 9095 return Top::Throw(Heap::illegal_argument_symbol()); 9096 } 9097 9098 // Clear all current stepping setup. 9099 Debug::ClearStepping(); 9100 9101 // Prepare step. 9102 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count); 9103 return Heap::undefined_value(); 9104} 9105 9106 9107// Clear all stepping set by PrepareStep. 9108static Object* Runtime_ClearStepping(Arguments args) { 9109 HandleScope scope; 9110 ASSERT(args.length() == 0); 9111 Debug::ClearStepping(); 9112 return Heap::undefined_value(); 9113} 9114 9115 9116// Creates a copy of the with context chain. The copy of the context chain is 9117// is linked to the function context supplied. 9118static Handle<Context> CopyWithContextChain(Handle<Context> context_chain, 9119 Handle<Context> function_context) { 9120 // At the bottom of the chain. Return the function context to link to. 9121 if (context_chain->is_function_context()) { 9122 return function_context; 9123 } 9124 9125 // Recursively copy the with contexts. 9126 Handle<Context> previous(context_chain->previous()); 9127 Handle<JSObject> extension(JSObject::cast(context_chain->extension())); 9128 return Factory::NewWithContext( 9129 CopyWithContextChain(function_context, previous), 9130 extension, 9131 context_chain->IsCatchContext()); 9132} 9133 9134 9135// Helper function to find or create the arguments object for 9136// Runtime_DebugEvaluate. 9137static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame, 9138 Handle<JSFunction> function, 9139 Handle<Code> code, 9140 const ScopeInfo<>* sinfo, 9141 Handle<Context> function_context) { 9142 // Try to find the value of 'arguments' to pass as parameter. If it is not 9143 // found (that is the debugged function does not reference 'arguments' and 9144 // does not support eval) then create an 'arguments' object. 9145 int index; 9146 if (sinfo->number_of_stack_slots() > 0) { 9147 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol()); 9148 if (index != -1) { 9149 return Handle<Object>(frame->GetExpression(index)); 9150 } 9151 } 9152 9153 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) { 9154 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(), 9155 NULL); 9156 if (index != -1) { 9157 return Handle<Object>(function_context->get(index)); 9158 } 9159 } 9160 9161 const int length = frame->GetProvidedParametersCount(); 9162 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length); 9163 Handle<FixedArray> array = Factory::NewFixedArray(length); 9164 9165 AssertNoAllocation no_gc; 9166 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); 9167 for (int i = 0; i < length; i++) { 9168 array->set(i, frame->GetParameter(i), mode); 9169 } 9170 arguments->set_elements(*array); 9171 return arguments; 9172} 9173 9174 9175// Evaluate a piece of JavaScript in the context of a stack frame for 9176// debugging. This is accomplished by creating a new context which in its 9177// extension part has all the parameters and locals of the function on the 9178// stack frame. A function which calls eval with the code to evaluate is then 9179// compiled in this context and called in this context. As this context 9180// replaces the context of the function on the stack frame a new (empty) 9181// function is created as well to be used as the closure for the context. 9182// This function and the context acts as replacements for the function on the 9183// stack frame presenting the same view of the values of parameters and 9184// local variables as if the piece of JavaScript was evaluated at the point 9185// where the function on the stack frame is currently stopped. 9186static Object* Runtime_DebugEvaluate(Arguments args) { 9187 HandleScope scope; 9188 9189 // Check the execution state and decode arguments frame and source to be 9190 // evaluated. 9191 ASSERT(args.length() == 4); 9192 Object* check_result = Runtime_CheckExecutionState(args); 9193 if (check_result->IsFailure()) return check_result; 9194 CONVERT_CHECKED(Smi, wrapped_id, args[1]); 9195 CONVERT_ARG_CHECKED(String, source, 2); 9196 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]); 9197 9198 // Handle the processing of break. 9199 DisableBreak disable_break_save(disable_break); 9200 9201 // Get the frame where the debugging is performed. 9202 StackFrame::Id id = UnwrapFrameId(wrapped_id); 9203 JavaScriptFrameIterator it(id); 9204 JavaScriptFrame* frame = it.frame(); 9205 Handle<JSFunction> function(JSFunction::cast(frame->function())); 9206 Handle<Code> code(function->code()); 9207 ScopeInfo<> sinfo(*code); 9208 9209 // Traverse the saved contexts chain to find the active context for the 9210 // selected frame. 9211 SaveContext* save = Top::save_context(); 9212 while (save != NULL && !save->below(frame)) { 9213 save = save->prev(); 9214 } 9215 ASSERT(save != NULL); 9216 SaveContext savex; 9217 Top::set_context(*(save->context())); 9218 9219 // Create the (empty) function replacing the function on the stack frame for 9220 // the purpose of evaluating in the context created below. It is important 9221 // that this function does not describe any parameters and local variables 9222 // in the context. If it does then this will cause problems with the lookup 9223 // in Context::Lookup, where context slots for parameters and local variables 9224 // are looked at before the extension object. 9225 Handle<JSFunction> go_between = 9226 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value()); 9227 go_between->set_context(function->context()); 9228#ifdef DEBUG 9229 ScopeInfo<> go_between_sinfo(go_between->shared()->code()); 9230 ASSERT(go_between_sinfo.number_of_parameters() == 0); 9231 ASSERT(go_between_sinfo.number_of_context_slots() == 0); 9232#endif 9233 9234 // Materialize the content of the local scope into a JSObject. 9235 Handle<JSObject> local_scope = MaterializeLocalScope(frame); 9236 9237 // Allocate a new context for the debug evaluation and set the extension 9238 // object build. 9239 Handle<Context> context = 9240 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between); 9241 context->set_extension(*local_scope); 9242 // Copy any with contexts present and chain them in front of this context. 9243 Handle<Context> frame_context(Context::cast(frame->context())); 9244 Handle<Context> function_context(frame_context->fcontext()); 9245 context = CopyWithContextChain(frame_context, context); 9246 9247 // Wrap the evaluation statement in a new function compiled in the newly 9248 // created context. The function has one parameter which has to be called 9249 // 'arguments'. This it to have access to what would have been 'arguments' in 9250 // the function being debugged. 9251 // function(arguments,__source__) {return eval(__source__);} 9252 static const char* source_str = 9253 "(function(arguments,__source__){return eval(__source__);})"; 9254 static const int source_str_length = StrLength(source_str); 9255 Handle<String> function_source = 9256 Factory::NewStringFromAscii(Vector<const char>(source_str, 9257 source_str_length)); 9258 Handle<SharedFunctionInfo> shared = 9259 Compiler::CompileEval(function_source, 9260 context, 9261 context->IsGlobalContext(), 9262 Compiler::DONT_VALIDATE_JSON); 9263 if (shared.is_null()) return Failure::Exception(); 9264 Handle<JSFunction> compiled_function = 9265 Factory::NewFunctionFromSharedFunctionInfo(shared, context); 9266 9267 // Invoke the result of the compilation to get the evaluation function. 9268 bool has_pending_exception; 9269 Handle<Object> receiver(frame->receiver()); 9270 Handle<Object> evaluation_function = 9271 Execution::Call(compiled_function, receiver, 0, NULL, 9272 &has_pending_exception); 9273 if (has_pending_exception) return Failure::Exception(); 9274 9275 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo, 9276 function_context); 9277 9278 // Invoke the evaluation function and return the result. 9279 const int argc = 2; 9280 Object** argv[argc] = { arguments.location(), 9281 Handle<Object>::cast(source).location() }; 9282 Handle<Object> result = 9283 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver, 9284 argc, argv, &has_pending_exception); 9285 if (has_pending_exception) return Failure::Exception(); 9286 9287 // Skip the global proxy as it has no properties and always delegates to the 9288 // real global object. 9289 if (result->IsJSGlobalProxy()) { 9290 result = Handle<JSObject>(JSObject::cast(result->GetPrototype())); 9291 } 9292 9293 return *result; 9294} 9295 9296 9297static Object* Runtime_DebugEvaluateGlobal(Arguments args) { 9298 HandleScope scope; 9299 9300 // Check the execution state and decode arguments frame and source to be 9301 // evaluated. 9302 ASSERT(args.length() == 3); 9303 Object* check_result = Runtime_CheckExecutionState(args); 9304 if (check_result->IsFailure()) return check_result; 9305 CONVERT_ARG_CHECKED(String, source, 1); 9306 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]); 9307 9308 // Handle the processing of break. 9309 DisableBreak disable_break_save(disable_break); 9310 9311 // Enter the top context from before the debugger was invoked. 9312 SaveContext save; 9313 SaveContext* top = &save; 9314 while (top != NULL && *top->context() == *Debug::debug_context()) { 9315 top = top->prev(); 9316 } 9317 if (top != NULL) { 9318 Top::set_context(*top->context()); 9319 } 9320 9321 // Get the global context now set to the top context from before the 9322 // debugger was invoked. 9323 Handle<Context> context = Top::global_context(); 9324 9325 // Compile the source to be evaluated. 9326 Handle<SharedFunctionInfo> shared = 9327 Compiler::CompileEval(source, 9328 context, 9329 true, 9330 Compiler::DONT_VALIDATE_JSON); 9331 if (shared.is_null()) return Failure::Exception(); 9332 Handle<JSFunction> compiled_function = 9333 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared, 9334 context)); 9335 9336 // Invoke the result of the compilation to get the evaluation function. 9337 bool has_pending_exception; 9338 Handle<Object> receiver = Top::global(); 9339 Handle<Object> result = 9340 Execution::Call(compiled_function, receiver, 0, NULL, 9341 &has_pending_exception); 9342 if (has_pending_exception) return Failure::Exception(); 9343 return *result; 9344} 9345 9346 9347static Object* Runtime_DebugGetLoadedScripts(Arguments args) { 9348 HandleScope scope; 9349 ASSERT(args.length() == 0); 9350 9351 // Fill the script objects. 9352 Handle<FixedArray> instances = Debug::GetLoadedScripts(); 9353 9354 // Convert the script objects to proper JS objects. 9355 for (int i = 0; i < instances->length(); i++) { 9356 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); 9357 // Get the script wrapper in a local handle before calling GetScriptWrapper, 9358 // because using 9359 // instances->set(i, *GetScriptWrapper(script)) 9360 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might 9361 // already have deferenced the instances handle. 9362 Handle<JSValue> wrapper = GetScriptWrapper(script); 9363 instances->set(i, *wrapper); 9364 } 9365 9366 // Return result as a JS array. 9367 Handle<JSObject> result = Factory::NewJSObject(Top::array_function()); 9368 Handle<JSArray>::cast(result)->SetContent(*instances); 9369 return *result; 9370} 9371 9372 9373// Helper function used by Runtime_DebugReferencedBy below. 9374static int DebugReferencedBy(JSObject* target, 9375 Object* instance_filter, int max_references, 9376 FixedArray* instances, int instances_size, 9377 JSFunction* arguments_function) { 9378 NoHandleAllocation ha; 9379 AssertNoAllocation no_alloc; 9380 9381 // Iterate the heap. 9382 int count = 0; 9383 JSObject* last = NULL; 9384 HeapIterator iterator; 9385 HeapObject* heap_obj = NULL; 9386 while (((heap_obj = iterator.next()) != NULL) && 9387 (max_references == 0 || count < max_references)) { 9388 // Only look at all JSObjects. 9389 if (heap_obj->IsJSObject()) { 9390 // Skip context extension objects and argument arrays as these are 9391 // checked in the context of functions using them. 9392 JSObject* obj = JSObject::cast(heap_obj); 9393 if (obj->IsJSContextExtensionObject() || 9394 obj->map()->constructor() == arguments_function) { 9395 continue; 9396 } 9397 9398 // Check if the JS object has a reference to the object looked for. 9399 if (obj->ReferencesObject(target)) { 9400 // Check instance filter if supplied. This is normally used to avoid 9401 // references from mirror objects (see Runtime_IsInPrototypeChain). 9402 if (!instance_filter->IsUndefined()) { 9403 Object* V = obj; 9404 while (true) { 9405 Object* prototype = V->GetPrototype(); 9406 if (prototype->IsNull()) { 9407 break; 9408 } 9409 if (instance_filter == prototype) { 9410 obj = NULL; // Don't add this object. 9411 break; 9412 } 9413 V = prototype; 9414 } 9415 } 9416 9417 if (obj != NULL) { 9418 // Valid reference found add to instance array if supplied an update 9419 // count. 9420 if (instances != NULL && count < instances_size) { 9421 instances->set(count, obj); 9422 } 9423 last = obj; 9424 count++; 9425 } 9426 } 9427 } 9428 } 9429 9430 // Check for circular reference only. This can happen when the object is only 9431 // referenced from mirrors and has a circular reference in which case the 9432 // object is not really alive and would have been garbage collected if not 9433 // referenced from the mirror. 9434 if (count == 1 && last == target) { 9435 count = 0; 9436 } 9437 9438 // Return the number of referencing objects found. 9439 return count; 9440} 9441 9442 9443// Scan the heap for objects with direct references to an object 9444// args[0]: the object to find references to 9445// args[1]: constructor function for instances to exclude (Mirror) 9446// args[2]: the the maximum number of objects to return 9447static Object* Runtime_DebugReferencedBy(Arguments args) { 9448 ASSERT(args.length() == 3); 9449 9450 // First perform a full GC in order to avoid references from dead objects. 9451 Heap::CollectAllGarbage(false); 9452 9453 // Check parameters. 9454 CONVERT_CHECKED(JSObject, target, args[0]); 9455 Object* instance_filter = args[1]; 9456 RUNTIME_ASSERT(instance_filter->IsUndefined() || 9457 instance_filter->IsJSObject()); 9458 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); 9459 RUNTIME_ASSERT(max_references >= 0); 9460 9461 // Get the constructor function for context extension and arguments array. 9462 JSObject* arguments_boilerplate = 9463 Top::context()->global_context()->arguments_boilerplate(); 9464 JSFunction* arguments_function = 9465 JSFunction::cast(arguments_boilerplate->map()->constructor()); 9466 9467 // Get the number of referencing objects. 9468 int count; 9469 count = DebugReferencedBy(target, instance_filter, max_references, 9470 NULL, 0, arguments_function); 9471 9472 // Allocate an array to hold the result. 9473 Object* object = Heap::AllocateFixedArray(count); 9474 if (object->IsFailure()) return object; 9475 FixedArray* instances = FixedArray::cast(object); 9476 9477 // Fill the referencing objects. 9478 count = DebugReferencedBy(target, instance_filter, max_references, 9479 instances, count, arguments_function); 9480 9481 // Return result as JS array. 9482 Object* result = 9483 Heap::AllocateJSObject( 9484 Top::context()->global_context()->array_function()); 9485 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances); 9486 return result; 9487} 9488 9489 9490// Helper function used by Runtime_DebugConstructedBy below. 9491static int DebugConstructedBy(JSFunction* constructor, int max_references, 9492 FixedArray* instances, int instances_size) { 9493 AssertNoAllocation no_alloc; 9494 9495 // Iterate the heap. 9496 int count = 0; 9497 HeapIterator iterator; 9498 HeapObject* heap_obj = NULL; 9499 while (((heap_obj = iterator.next()) != NULL) && 9500 (max_references == 0 || count < max_references)) { 9501 // Only look at all JSObjects. 9502 if (heap_obj->IsJSObject()) { 9503 JSObject* obj = JSObject::cast(heap_obj); 9504 if (obj->map()->constructor() == constructor) { 9505 // Valid reference found add to instance array if supplied an update 9506 // count. 9507 if (instances != NULL && count < instances_size) { 9508 instances->set(count, obj); 9509 } 9510 count++; 9511 } 9512 } 9513 } 9514 9515 // Return the number of referencing objects found. 9516 return count; 9517} 9518 9519 9520// Scan the heap for objects constructed by a specific function. 9521// args[0]: the constructor to find instances of 9522// args[1]: the the maximum number of objects to return 9523static Object* Runtime_DebugConstructedBy(Arguments args) { 9524 ASSERT(args.length() == 2); 9525 9526 // First perform a full GC in order to avoid dead objects. 9527 Heap::CollectAllGarbage(false); 9528 9529 // Check parameters. 9530 CONVERT_CHECKED(JSFunction, constructor, args[0]); 9531 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); 9532 RUNTIME_ASSERT(max_references >= 0); 9533 9534 // Get the number of referencing objects. 9535 int count; 9536 count = DebugConstructedBy(constructor, max_references, NULL, 0); 9537 9538 // Allocate an array to hold the result. 9539 Object* object = Heap::AllocateFixedArray(count); 9540 if (object->IsFailure()) return object; 9541 FixedArray* instances = FixedArray::cast(object); 9542 9543 // Fill the referencing objects. 9544 count = DebugConstructedBy(constructor, max_references, instances, count); 9545 9546 // Return result as JS array. 9547 Object* result = 9548 Heap::AllocateJSObject( 9549 Top::context()->global_context()->array_function()); 9550 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances); 9551 return result; 9552} 9553 9554 9555// Find the effective prototype object as returned by __proto__. 9556// args[0]: the object to find the prototype for. 9557static Object* Runtime_DebugGetPrototype(Arguments args) { 9558 ASSERT(args.length() == 1); 9559 9560 CONVERT_CHECKED(JSObject, obj, args[0]); 9561 9562 // Use the __proto__ accessor. 9563 return Accessors::ObjectPrototype.getter(obj, NULL); 9564} 9565 9566 9567static Object* Runtime_SystemBreak(Arguments args) { 9568 ASSERT(args.length() == 0); 9569 CPU::DebugBreak(); 9570 return Heap::undefined_value(); 9571} 9572 9573 9574static Object* Runtime_DebugDisassembleFunction(Arguments args) { 9575#ifdef DEBUG 9576 HandleScope scope; 9577 ASSERT(args.length() == 1); 9578 // Get the function and make sure it is compiled. 9579 CONVERT_ARG_CHECKED(JSFunction, func, 0); 9580 Handle<SharedFunctionInfo> shared(func->shared()); 9581 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) { 9582 return Failure::Exception(); 9583 } 9584 func->code()->PrintLn(); 9585#endif // DEBUG 9586 return Heap::undefined_value(); 9587} 9588 9589 9590static Object* Runtime_DebugDisassembleConstructor(Arguments args) { 9591#ifdef DEBUG 9592 HandleScope scope; 9593 ASSERT(args.length() == 1); 9594 // Get the function and make sure it is compiled. 9595 CONVERT_ARG_CHECKED(JSFunction, func, 0); 9596 Handle<SharedFunctionInfo> shared(func->shared()); 9597 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) { 9598 return Failure::Exception(); 9599 } 9600 shared->construct_stub()->PrintLn(); 9601#endif // DEBUG 9602 return Heap::undefined_value(); 9603} 9604 9605 9606static Object* Runtime_FunctionGetInferredName(Arguments args) { 9607 NoHandleAllocation ha; 9608 ASSERT(args.length() == 1); 9609 9610 CONVERT_CHECKED(JSFunction, f, args[0]); 9611 return f->shared()->inferred_name(); 9612} 9613 9614 9615static int FindSharedFunctionInfosForScript(Script* script, 9616 FixedArray* buffer) { 9617 AssertNoAllocation no_allocations; 9618 9619 int counter = 0; 9620 int buffer_size = buffer->length(); 9621 HeapIterator iterator; 9622 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 9623 ASSERT(obj != NULL); 9624 if (!obj->IsSharedFunctionInfo()) { 9625 continue; 9626 } 9627 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); 9628 if (shared->script() != script) { 9629 continue; 9630 } 9631 if (counter < buffer_size) { 9632 buffer->set(counter, shared); 9633 } 9634 counter++; 9635 } 9636 return counter; 9637} 9638 9639// For a script finds all SharedFunctionInfo's in the heap that points 9640// to this script. Returns JSArray of SharedFunctionInfo wrapped 9641// in OpaqueReferences. 9642static Object* Runtime_LiveEditFindSharedFunctionInfosForScript( 9643 Arguments args) { 9644 ASSERT(args.length() == 1); 9645 HandleScope scope; 9646 CONVERT_CHECKED(JSValue, script_value, args[0]); 9647 9648 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); 9649 9650 const int kBufferSize = 32; 9651 9652 Handle<FixedArray> array; 9653 array = Factory::NewFixedArray(kBufferSize); 9654 int number = FindSharedFunctionInfosForScript(*script, *array); 9655 if (number > kBufferSize) { 9656 array = Factory::NewFixedArray(number); 9657 FindSharedFunctionInfosForScript(*script, *array); 9658 } 9659 9660 Handle<JSArray> result = Factory::NewJSArrayWithElements(array); 9661 result->set_length(Smi::FromInt(number)); 9662 9663 LiveEdit::WrapSharedFunctionInfos(result); 9664 9665 return *result; 9666} 9667 9668// For a script calculates compilation information about all its functions. 9669// The script source is explicitly specified by the second argument. 9670// The source of the actual script is not used, however it is important that 9671// all generated code keeps references to this particular instance of script. 9672// Returns a JSArray of compilation infos. The array is ordered so that 9673// each function with all its descendant is always stored in a continues range 9674// with the function itself going first. The root function is a script function. 9675static Object* Runtime_LiveEditGatherCompileInfo(Arguments args) { 9676 ASSERT(args.length() == 2); 9677 HandleScope scope; 9678 CONVERT_CHECKED(JSValue, script, args[0]); 9679 CONVERT_ARG_CHECKED(String, source, 1); 9680 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 9681 9682 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source); 9683 9684 if (Top::has_pending_exception()) { 9685 return Failure::Exception(); 9686 } 9687 9688 return result; 9689} 9690 9691// Changes the source of the script to a new_source. 9692// If old_script_name is provided (i.e. is a String), also creates a copy of 9693// the script with its original source and sends notification to debugger. 9694static Object* Runtime_LiveEditReplaceScript(Arguments args) { 9695 ASSERT(args.length() == 3); 9696 HandleScope scope; 9697 CONVERT_CHECKED(JSValue, original_script_value, args[0]); 9698 CONVERT_ARG_CHECKED(String, new_source, 1); 9699 Handle<Object> old_script_name(args[2]); 9700 9701 CONVERT_CHECKED(Script, original_script_pointer, 9702 original_script_value->value()); 9703 Handle<Script> original_script(original_script_pointer); 9704 9705 Object* old_script = LiveEdit::ChangeScriptSource(original_script, 9706 new_source, 9707 old_script_name); 9708 9709 if (old_script->IsScript()) { 9710 Handle<Script> script_handle(Script::cast(old_script)); 9711 return *(GetScriptWrapper(script_handle)); 9712 } else { 9713 return Heap::null_value(); 9714 } 9715} 9716 9717// Replaces code of SharedFunctionInfo with a new one. 9718static Object* Runtime_LiveEditReplaceFunctionCode(Arguments args) { 9719 ASSERT(args.length() == 2); 9720 HandleScope scope; 9721 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0); 9722 CONVERT_ARG_CHECKED(JSArray, shared_info, 1); 9723 9724 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); 9725} 9726 9727// Connects SharedFunctionInfo to another script. 9728static Object* Runtime_LiveEditFunctionSetScript(Arguments args) { 9729 ASSERT(args.length() == 2); 9730 HandleScope scope; 9731 Handle<Object> function_object(args[0]); 9732 Handle<Object> script_object(args[1]); 9733 9734 if (function_object->IsJSValue()) { 9735 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); 9736 if (script_object->IsJSValue()) { 9737 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value()); 9738 script_object = Handle<Object>(script); 9739 } 9740 9741 LiveEdit::SetFunctionScript(function_wrapper, script_object); 9742 } else { 9743 // Just ignore this. We may not have a SharedFunctionInfo for some functions 9744 // and we check it in this function. 9745 } 9746 9747 return Heap::undefined_value(); 9748} 9749 9750 9751// In a code of a parent function replaces original function as embedded object 9752// with a substitution one. 9753static Object* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) { 9754 ASSERT(args.length() == 3); 9755 HandleScope scope; 9756 9757 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0); 9758 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1); 9759 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2); 9760 9761 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper, 9762 subst_wrapper); 9763 9764 return Heap::undefined_value(); 9765} 9766 9767 9768// Updates positions of a shared function info (first parameter) according 9769// to script source change. Text change is described in second parameter as 9770// array of groups of 3 numbers: 9771// (change_begin, change_end, change_end_new_position). 9772// Each group describes a change in text; groups are sorted by change_begin. 9773static Object* Runtime_LiveEditPatchFunctionPositions(Arguments args) { 9774 ASSERT(args.length() == 2); 9775 HandleScope scope; 9776 CONVERT_ARG_CHECKED(JSArray, shared_array, 0); 9777 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1); 9778 9779 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array); 9780} 9781 9782 9783// For array of SharedFunctionInfo's (each wrapped in JSValue) 9784// checks that none of them have activations on stacks (of any thread). 9785// Returns array of the same length with corresponding results of 9786// LiveEdit::FunctionPatchabilityStatus type. 9787static Object* Runtime_LiveEditCheckAndDropActivations(Arguments args) { 9788 ASSERT(args.length() == 2); 9789 HandleScope scope; 9790 CONVERT_ARG_CHECKED(JSArray, shared_array, 0); 9791 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]); 9792 9793 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); 9794} 9795 9796// Compares 2 strings line-by-line and returns diff in form of JSArray of 9797// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks. 9798static Object* Runtime_LiveEditCompareStringsLinewise(Arguments args) { 9799 ASSERT(args.length() == 2); 9800 HandleScope scope; 9801 CONVERT_ARG_CHECKED(String, s1, 0); 9802 CONVERT_ARG_CHECKED(String, s2, 1); 9803 9804 return *LiveEdit::CompareStringsLinewise(s1, s2); 9805} 9806 9807 9808 9809// A testing entry. Returns statement position which is the closest to 9810// source_position. 9811static Object* Runtime_GetFunctionCodePositionFromSource(Arguments args) { 9812 ASSERT(args.length() == 2); 9813 HandleScope scope; 9814 CONVERT_ARG_CHECKED(JSFunction, function, 0); 9815 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 9816 9817 Handle<Code> code(function->code()); 9818 9819 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION); 9820 int closest_pc = 0; 9821 int distance = kMaxInt; 9822 while (!it.done()) { 9823 int statement_position = static_cast<int>(it.rinfo()->data()); 9824 // Check if this break point is closer that what was previously found. 9825 if (source_position <= statement_position && 9826 statement_position - source_position < distance) { 9827 closest_pc = 9828 static_cast<int>(it.rinfo()->pc() - code->instruction_start()); 9829 distance = statement_position - source_position; 9830 // Check whether we can't get any closer. 9831 if (distance == 0) break; 9832 } 9833 it.next(); 9834 } 9835 9836 return Smi::FromInt(closest_pc); 9837} 9838 9839 9840// Calls specified function with or without entering the debugger. 9841// This is used in unit tests to run code as if debugger is entered or simply 9842// to have a stack with C++ frame in the middle. 9843static Object* Runtime_ExecuteInDebugContext(Arguments args) { 9844 ASSERT(args.length() == 2); 9845 HandleScope scope; 9846 CONVERT_ARG_CHECKED(JSFunction, function, 0); 9847 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]); 9848 9849 Handle<Object> result; 9850 bool pending_exception; 9851 { 9852 if (without_debugger) { 9853 result = Execution::Call(function, Top::global(), 0, NULL, 9854 &pending_exception); 9855 } else { 9856 EnterDebugger enter_debugger; 9857 result = Execution::Call(function, Top::global(), 0, NULL, 9858 &pending_exception); 9859 } 9860 } 9861 if (!pending_exception) { 9862 return *result; 9863 } else { 9864 return Failure::Exception(); 9865 } 9866} 9867 9868 9869#endif // ENABLE_DEBUGGER_SUPPORT 9870 9871#ifdef ENABLE_LOGGING_AND_PROFILING 9872 9873static Object* Runtime_ProfilerResume(Arguments args) { 9874 NoHandleAllocation ha; 9875 ASSERT(args.length() == 2); 9876 9877 CONVERT_CHECKED(Smi, smi_modules, args[0]); 9878 CONVERT_CHECKED(Smi, smi_tag, args[1]); 9879 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value()); 9880 return Heap::undefined_value(); 9881} 9882 9883 9884static Object* Runtime_ProfilerPause(Arguments args) { 9885 NoHandleAllocation ha; 9886 ASSERT(args.length() == 2); 9887 9888 CONVERT_CHECKED(Smi, smi_modules, args[0]); 9889 CONVERT_CHECKED(Smi, smi_tag, args[1]); 9890 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value()); 9891 return Heap::undefined_value(); 9892} 9893 9894#endif // ENABLE_LOGGING_AND_PROFILING 9895 9896// Finds the script object from the script data. NOTE: This operation uses 9897// heap traversal to find the function generated for the source position 9898// for the requested break point. For lazily compiled functions several heap 9899// traversals might be required rendering this operation as a rather slow 9900// operation. However for setting break points which is normally done through 9901// some kind of user interaction the performance is not crucial. 9902static Handle<Object> Runtime_GetScriptFromScriptName( 9903 Handle<String> script_name) { 9904 // Scan the heap for Script objects to find the script with the requested 9905 // script data. 9906 Handle<Script> script; 9907 HeapIterator iterator; 9908 HeapObject* obj = NULL; 9909 while (script.is_null() && ((obj = iterator.next()) != NULL)) { 9910 // If a script is found check if it has the script data requested. 9911 if (obj->IsScript()) { 9912 if (Script::cast(obj)->name()->IsString()) { 9913 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { 9914 script = Handle<Script>(Script::cast(obj)); 9915 } 9916 } 9917 } 9918 } 9919 9920 // If no script with the requested script data is found return undefined. 9921 if (script.is_null()) return Factory::undefined_value(); 9922 9923 // Return the script found. 9924 return GetScriptWrapper(script); 9925} 9926 9927 9928// Get the script object from script data. NOTE: Regarding performance 9929// see the NOTE for GetScriptFromScriptData. 9930// args[0]: script data for the script to find the source for 9931static Object* Runtime_GetScript(Arguments args) { 9932 HandleScope scope; 9933 9934 ASSERT(args.length() == 1); 9935 9936 CONVERT_CHECKED(String, script_name, args[0]); 9937 9938 // Find the requested script. 9939 Handle<Object> result = 9940 Runtime_GetScriptFromScriptName(Handle<String>(script_name)); 9941 return *result; 9942} 9943 9944 9945// Determines whether the given stack frame should be displayed in 9946// a stack trace. The caller is the error constructor that asked 9947// for the stack trace to be collected. The first time a construct 9948// call to this function is encountered it is skipped. The seen_caller 9949// in/out parameter is used to remember if the caller has been seen 9950// yet. 9951static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller, 9952 bool* seen_caller) { 9953 // Only display JS frames. 9954 if (!raw_frame->is_java_script()) 9955 return false; 9956 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); 9957 Object* raw_fun = frame->function(); 9958 // Not sure when this can happen but skip it just in case. 9959 if (!raw_fun->IsJSFunction()) 9960 return false; 9961 if ((raw_fun == caller) && !(*seen_caller)) { 9962 *seen_caller = true; 9963 return false; 9964 } 9965 // Skip all frames until we've seen the caller. Also, skip the most 9966 // obvious builtin calls. Some builtin calls (such as Number.ADD 9967 // which is invoked using 'call') are very difficult to recognize 9968 // so we're leaving them in for now. 9969 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject(); 9970} 9971 9972 9973// Collect the raw data for a stack trace. Returns an array of three 9974// element segments each containing a receiver, function and native 9975// code offset. 9976static Object* Runtime_CollectStackTrace(Arguments args) { 9977 ASSERT_EQ(args.length(), 2); 9978 Handle<Object> caller = args.at<Object>(0); 9979 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]); 9980 9981 HandleScope scope; 9982 9983 limit = Max(limit, 0); // Ensure that limit is not negative. 9984 int initial_size = Min(limit, 10); 9985 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3); 9986 9987 StackFrameIterator iter; 9988 // If the caller parameter is a function we skip frames until we're 9989 // under it before starting to collect. 9990 bool seen_caller = !caller->IsJSFunction(); 9991 int cursor = 0; 9992 int frames_seen = 0; 9993 while (!iter.done() && frames_seen < limit) { 9994 StackFrame* raw_frame = iter.frame(); 9995 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) { 9996 frames_seen++; 9997 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); 9998 Object* recv = frame->receiver(); 9999 Object* fun = frame->function(); 10000 Address pc = frame->pc(); 10001 Address start = frame->code()->address(); 10002 Smi* offset = Smi::FromInt(static_cast<int>(pc - start)); 10003 FixedArray* elements = FixedArray::cast(result->elements()); 10004 if (cursor + 2 < elements->length()) { 10005 elements->set(cursor++, recv); 10006 elements->set(cursor++, fun); 10007 elements->set(cursor++, offset); 10008 } else { 10009 HandleScope scope; 10010 Handle<Object> recv_handle(recv); 10011 Handle<Object> fun_handle(fun); 10012 SetElement(result, cursor++, recv_handle); 10013 SetElement(result, cursor++, fun_handle); 10014 SetElement(result, cursor++, Handle<Smi>(offset)); 10015 } 10016 } 10017 iter.Advance(); 10018 } 10019 10020 result->set_length(Smi::FromInt(cursor)); 10021 return *result; 10022} 10023 10024 10025// Returns V8 version as a string. 10026static Object* Runtime_GetV8Version(Arguments args) { 10027 ASSERT_EQ(args.length(), 0); 10028 10029 NoHandleAllocation ha; 10030 10031 const char* version_string = v8::V8::GetVersion(); 10032 10033 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED); 10034} 10035 10036 10037static Object* Runtime_Abort(Arguments args) { 10038 ASSERT(args.length() == 2); 10039 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) + 10040 Smi::cast(args[1])->value()); 10041 Top::PrintStack(); 10042 OS::Abort(); 10043 UNREACHABLE(); 10044 return NULL; 10045} 10046 10047 10048static Object* Runtime_DeleteHandleScopeExtensions(Arguments args) { 10049 ASSERT(args.length() == 0); 10050 HandleScope::DeleteExtensions(); 10051 return Heap::undefined_value(); 10052} 10053 10054 10055static Object* CacheMiss(FixedArray* cache_obj, int index, Object* key_obj) { 10056 ASSERT(index % 2 == 0); // index of the key 10057 ASSERT(index >= JSFunctionResultCache::kEntriesIndex); 10058 ASSERT(index < cache_obj->length()); 10059 10060 HandleScope scope; 10061 10062 Handle<FixedArray> cache(cache_obj); 10063 Handle<Object> key(key_obj); 10064 Handle<JSFunction> factory(JSFunction::cast( 10065 cache->get(JSFunctionResultCache::kFactoryIndex))); 10066 // TODO(antonm): consider passing a receiver when constructing a cache. 10067 Handle<Object> receiver(Top::global_context()->global()); 10068 10069 Handle<Object> value; 10070 { 10071 // This handle is nor shared, nor used later, so it's safe. 10072 Object** argv[] = { key.location() }; 10073 bool pending_exception = false; 10074 value = Execution::Call(factory, 10075 receiver, 10076 1, 10077 argv, 10078 &pending_exception); 10079 if (pending_exception) return Failure::Exception(); 10080 } 10081 10082 cache->set(index, *key); 10083 cache->set(index + 1, *value); 10084 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index)); 10085 10086 return *value; 10087} 10088 10089 10090static Object* Runtime_GetFromCache(Arguments args) { 10091 // This is only called from codegen, so checks might be more lax. 10092 CONVERT_CHECKED(FixedArray, cache, args[0]); 10093 Object* key = args[1]; 10094 10095 const int finger_index = 10096 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value(); 10097 10098 Object* o = cache->get(finger_index); 10099 if (o == key) { 10100 // The fastest case: hit the same place again. 10101 return cache->get(finger_index + 1); 10102 } 10103 10104 for (int i = finger_index - 2; 10105 i >= JSFunctionResultCache::kEntriesIndex; 10106 i -= 2) { 10107 o = cache->get(i); 10108 if (o == key) { 10109 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i)); 10110 return cache->get(i + 1); 10111 } 10112 } 10113 10114 const int size = 10115 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value(); 10116 ASSERT(size <= cache->length()); 10117 10118 for (int i = size - 2; i > finger_index; i -= 2) { 10119 o = cache->get(i); 10120 if (o == key) { 10121 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i)); 10122 return cache->get(i + 1); 10123 } 10124 } 10125 10126 // Cache miss. If we have spare room, put new data into it, otherwise 10127 // evict post finger entry which must be least recently used. 10128 if (size < cache->length()) { 10129 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2)); 10130 return CacheMiss(cache, size, key); 10131 } else { 10132 int target_index = finger_index + JSFunctionResultCache::kEntrySize; 10133 if (target_index == cache->length()) { 10134 target_index = JSFunctionResultCache::kEntriesIndex; 10135 } 10136 return CacheMiss(cache, target_index, key); 10137 } 10138} 10139 10140#ifdef DEBUG 10141// ListNatives is ONLY used by the fuzz-natives.js in debug mode 10142// Exclude the code in release mode. 10143static Object* Runtime_ListNatives(Arguments args) { 10144 ASSERT(args.length() == 0); 10145 HandleScope scope; 10146 Handle<JSArray> result = Factory::NewJSArray(0); 10147 int index = 0; 10148 bool inline_runtime_functions = false; 10149#define ADD_ENTRY(Name, argc, ressize) \ 10150 { \ 10151 HandleScope inner; \ 10152 Handle<String> name; \ 10153 /* Inline runtime functions have an underscore in front of the name. */ \ 10154 if (inline_runtime_functions) { \ 10155 name = Factory::NewStringFromAscii( \ 10156 Vector<const char>("_" #Name, StrLength("_" #Name))); \ 10157 } else { \ 10158 name = Factory::NewStringFromAscii( \ 10159 Vector<const char>(#Name, StrLength(#Name))); \ 10160 } \ 10161 Handle<JSArray> pair = Factory::NewJSArray(0); \ 10162 SetElement(pair, 0, name); \ 10163 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \ 10164 SetElement(result, index++, pair); \ 10165 } 10166 inline_runtime_functions = false; 10167 RUNTIME_FUNCTION_LIST(ADD_ENTRY) 10168 inline_runtime_functions = true; 10169 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY) 10170#undef ADD_ENTRY 10171 return *result; 10172} 10173#endif 10174 10175 10176static Object* Runtime_Log(Arguments args) { 10177 ASSERT(args.length() == 2); 10178 CONVERT_CHECKED(String, format, args[0]); 10179 CONVERT_CHECKED(JSArray, elms, args[1]); 10180 Vector<const char> chars = format->ToAsciiVector(); 10181 Logger::LogRuntime(chars, elms); 10182 return Heap::undefined_value(); 10183} 10184 10185 10186static Object* Runtime_IS_VAR(Arguments args) { 10187 UNREACHABLE(); // implemented as macro in the parser 10188 return NULL; 10189} 10190 10191 10192// ---------------------------------------------------------------------------- 10193// Implementation of Runtime 10194 10195#define F(name, nargs, ressize) \ 10196 { #name, FUNCTION_ADDR(Runtime_##name), nargs, \ 10197 static_cast<int>(Runtime::k##name), ressize }, 10198 10199static Runtime::Function Runtime_functions[] = { 10200 RUNTIME_FUNCTION_LIST(F) 10201 { NULL, NULL, 0, -1, 0 } 10202}; 10203 10204#undef F 10205 10206 10207Runtime::Function* Runtime::FunctionForId(FunctionId fid) { 10208 ASSERT(0 <= fid && fid < kNofFunctions); 10209 return &Runtime_functions[fid]; 10210} 10211 10212 10213Runtime::Function* Runtime::FunctionForName(const char* name) { 10214 for (Function* f = Runtime_functions; f->name != NULL; f++) { 10215 if (strcmp(f->name, name) == 0) { 10216 return f; 10217 } 10218 } 10219 return NULL; 10220} 10221 10222 10223void Runtime::PerformGC(Object* result) { 10224 Failure* failure = Failure::cast(result); 10225 if (failure->IsRetryAfterGC()) { 10226 // Try to do a garbage collection; ignore it if it fails. The C 10227 // entry stub will throw an out-of-memory exception in that case. 10228 Heap::CollectGarbage(failure->requested(), failure->allocation_space()); 10229 } else { 10230 // Handle last resort GC and make sure to allow future allocations 10231 // to grow the heap without causing GCs (if possible). 10232 Counters::gc_last_resort_from_js.Increment(); 10233 Heap::CollectAllGarbage(false); 10234 } 10235} 10236 10237 10238} } // namespace v8::internal 10239