runtime.cc revision 888f6729be6a6f6fbe246cb5a9f122e2dbe455b7
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 "compiler.h" 36#include "cpu.h" 37#include "dateparser-inl.h" 38#include "debug.h" 39#include "execution.h" 40#include "jsregexp.h" 41#include "parser.h" 42#include "platform.h" 43#include "runtime.h" 44#include "scopeinfo.h" 45#include "smart-pointer.h" 46#include "stub-cache.h" 47#include "v8threads.h" 48 49namespace v8 { 50namespace internal { 51 52 53#define RUNTIME_ASSERT(value) \ 54 if (!(value)) return Top::ThrowIllegalOperation(); 55 56// Cast the given object to a value of the specified type and store 57// it in a variable with the given name. If the object is not of the 58// expected type call IllegalOperation and return. 59#define CONVERT_CHECKED(Type, name, obj) \ 60 RUNTIME_ASSERT(obj->Is##Type()); \ 61 Type* name = Type::cast(obj); 62 63#define CONVERT_ARG_CHECKED(Type, name, index) \ 64 RUNTIME_ASSERT(args[index]->Is##Type()); \ 65 Handle<Type> name = args.at<Type>(index); 66 67// Cast the given object to a boolean and store it in a variable with 68// the given name. If the object is not a boolean call IllegalOperation 69// and return. 70#define CONVERT_BOOLEAN_CHECKED(name, obj) \ 71 RUNTIME_ASSERT(obj->IsBoolean()); \ 72 bool name = (obj)->IsTrue(); 73 74// Cast the given object to a Smi and store its value in an int variable 75// with the given name. If the object is not a Smi call IllegalOperation 76// and return. 77#define CONVERT_SMI_CHECKED(name, obj) \ 78 RUNTIME_ASSERT(obj->IsSmi()); \ 79 int name = Smi::cast(obj)->value(); 80 81// Cast the given object to a double and store it in a variable with 82// the given name. If the object is not a number (as opposed to 83// the number not-a-number) call IllegalOperation and return. 84#define CONVERT_DOUBLE_CHECKED(name, obj) \ 85 RUNTIME_ASSERT(obj->IsNumber()); \ 86 double name = (obj)->Number(); 87 88// Call the specified converter on the object *comand store the result in 89// a variable of the specified type with the given name. If the 90// object is not a Number call IllegalOperation and return. 91#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ 92 RUNTIME_ASSERT(obj->IsNumber()); \ 93 type name = NumberTo##Type(obj); 94 95// Non-reentrant string buffer for efficient general use in this file. 96static StaticResource<StringInputBuffer> runtime_string_input_buffer; 97 98 99static Object* DeepCopyBoilerplate(JSObject* boilerplate) { 100 StackLimitCheck check; 101 if (check.HasOverflowed()) return Top::StackOverflow(); 102 103 Object* result = Heap::CopyJSObject(boilerplate); 104 if (result->IsFailure()) return result; 105 JSObject* copy = JSObject::cast(result); 106 107 // Deep copy local properties. 108 if (copy->HasFastProperties()) { 109 FixedArray* properties = copy->properties(); 110 WriteBarrierMode mode = properties->GetWriteBarrierMode(); 111 for (int i = 0; i < properties->length(); i++) { 112 Object* value = properties->get(i); 113 if (value->IsJSObject()) { 114 JSObject* jsObject = JSObject::cast(value); 115 result = DeepCopyBoilerplate(jsObject); 116 if (result->IsFailure()) return result; 117 properties->set(i, result, mode); 118 } 119 } 120 mode = copy->GetWriteBarrierMode(); 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* jsObject = JSObject::cast(value); 126 result = DeepCopyBoilerplate(jsObject); 127 if (result->IsFailure()) return result; 128 copy->InObjectPropertyAtPut(i, result, mode); 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* keyString = String::cast(names->get(i)); 139 PropertyAttributes attributes = 140 copy->GetLocalPropertyAttribute(keyString); 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(keyString, &attributes); 146 ASSERT(!value->IsFailure()); 147 if (value->IsJSObject()) { 148 JSObject* jsObject = JSObject::cast(value); 149 result = DeepCopyBoilerplate(jsObject); 150 if (result->IsFailure()) return result; 151 result = copy->SetProperty(keyString, 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 WriteBarrierMode mode = elements->GetWriteBarrierMode(); 164 for (int i = 0; i < elements->length(); i++) { 165 Object* value = elements->get(i); 166 if (value->IsJSObject()) { 167 JSObject* jsObject = JSObject::cast(value); 168 result = DeepCopyBoilerplate(jsObject); 169 if (result->IsFailure()) return result; 170 elements->set(i, result, mode); 171 } 172 } 173 break; 174 } 175 case JSObject::DICTIONARY_ELEMENTS: { 176 NumberDictionary* element_dictionary = copy->element_dictionary(); 177 int capacity = element_dictionary->Capacity(); 178 for (int i = 0; i < capacity; i++) { 179 Object* k = element_dictionary->KeyAt(i); 180 if (element_dictionary->IsKey(k)) { 181 Object* value = element_dictionary->ValueAt(i); 182 if (value->IsJSObject()) { 183 JSObject* jsObject = JSObject::cast(value); 184 result = DeepCopyBoilerplate(jsObject); 185 if (result->IsFailure()) return result; 186 element_dictionary->ValueAtPut(i, result); 187 } 188 } 189 } 190 break; 191 } 192 default: 193 UNREACHABLE(); 194 break; 195 } 196 return copy; 197} 198 199 200static Object* Runtime_CloneLiteralBoilerplate(Arguments args) { 201 CONVERT_CHECKED(JSObject, boilerplate, args[0]); 202 return DeepCopyBoilerplate(boilerplate); 203} 204 205 206static Object* Runtime_CloneShallowLiteralBoilerplate(Arguments args) { 207 CONVERT_CHECKED(JSObject, boilerplate, args[0]); 208 return Heap::CopyJSObject(boilerplate); 209} 210 211 212static Handle<Map> ComputeObjectLiteralMap( 213 Handle<Context> context, 214 Handle<FixedArray> constant_properties, 215 bool* is_result_from_cache) { 216 int number_of_properties = constant_properties->length() / 2; 217 if (FLAG_canonicalize_object_literal_maps) { 218 // First find prefix of consecutive symbol keys. 219 int number_of_symbol_keys = 0; 220 while ((number_of_symbol_keys < number_of_properties) && 221 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) { 222 number_of_symbol_keys++; 223 } 224 // Based on the number of prefix symbols key we decide whether 225 // to use the map cache in the global context. 226 const int kMaxKeys = 10; 227 if ((number_of_symbol_keys == number_of_properties) && 228 (number_of_symbol_keys < kMaxKeys)) { 229 // Create the fixed array with the key. 230 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys); 231 for (int i = 0; i < number_of_symbol_keys; i++) { 232 keys->set(i, constant_properties->get(i*2)); 233 } 234 *is_result_from_cache = true; 235 return Factory::ObjectLiteralMapFromCache(context, keys); 236 } 237 } 238 *is_result_from_cache = false; 239 return Factory::CopyMap( 240 Handle<Map>(context->object_function()->initial_map()), 241 number_of_properties); 242} 243 244 245static Handle<Object> CreateLiteralBoilerplate( 246 Handle<FixedArray> literals, 247 Handle<FixedArray> constant_properties); 248 249 250static Handle<Object> CreateObjectLiteralBoilerplate( 251 Handle<FixedArray> literals, 252 Handle<FixedArray> constant_properties) { 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 { // Add the constant properties to the boilerplate. 269 int length = constant_properties->length(); 270 OptimizedObjectForAddingMultipleProperties opt(boilerplate, 271 length / 2, 272 !is_result_from_cache); 273 for (int index = 0; index < length; index +=2) { 274 Handle<Object> key(constant_properties->get(index+0)); 275 Handle<Object> value(constant_properties->get(index+1)); 276 if (value->IsFixedArray()) { 277 // The value contains the constant_properties of a 278 // simple object literal. 279 Handle<FixedArray> array = Handle<FixedArray>::cast(value); 280 value = CreateLiteralBoilerplate(literals, array); 281 if (value.is_null()) return value; 282 } 283 Handle<Object> result; 284 uint32_t element_index = 0; 285 if (key->IsSymbol()) { 286 // If key is a symbol it is not an array element. 287 Handle<String> name(String::cast(*key)); 288 ASSERT(!name->AsArrayIndex(&element_index)); 289 result = SetProperty(boilerplate, name, value, NONE); 290 } else if (Array::IndexFromObject(*key, &element_index)) { 291 // Array index (uint32). 292 result = SetElement(boilerplate, element_index, value); 293 } else { 294 // Non-uint32 number. 295 ASSERT(key->IsNumber()); 296 double num = key->Number(); 297 char arr[100]; 298 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 299 const char* str = DoubleToCString(num, buffer); 300 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); 301 result = SetProperty(boilerplate, name, value, NONE); 302 } 303 // If setting the property on the boilerplate throws an 304 // exception, the exception is converted to an empty handle in 305 // the handle based operations. In that case, we need to 306 // convert back to an exception. 307 if (result.is_null()) return result; 308 } 309 } 310 311 return boilerplate; 312} 313 314 315static Handle<Object> CreateArrayLiteralBoilerplate( 316 Handle<FixedArray> literals, 317 Handle<FixedArray> elements) { 318 // Create the JSArray. 319 Handle<JSFunction> constructor( 320 JSFunction::GlobalContextFromLiterals(*literals)->array_function()); 321 Handle<Object> object = Factory::NewJSObject(constructor); 322 323 Handle<Object> copied_elements = Factory::CopyFixedArray(elements); 324 325 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements); 326 for (int i = 0; i < content->length(); i++) { 327 if (content->get(i)->IsFixedArray()) { 328 // The value contains the constant_properties of a 329 // simple object literal. 330 Handle<FixedArray> fa(FixedArray::cast(content->get(i))); 331 Handle<Object> result = 332 CreateLiteralBoilerplate(literals, fa); 333 if (result.is_null()) return result; 334 content->set(i, *result); 335 } 336 } 337 338 // Set the elements. 339 Handle<JSArray>::cast(object)->SetContent(*content); 340 return object; 341} 342 343 344static Handle<Object> CreateLiteralBoilerplate( 345 Handle<FixedArray> literals, 346 Handle<FixedArray> array) { 347 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); 348 switch (CompileTimeValue::GetType(array)) { 349 case CompileTimeValue::OBJECT_LITERAL: 350 return CreateObjectLiteralBoilerplate(literals, elements); 351 case CompileTimeValue::ARRAY_LITERAL: 352 return CreateArrayLiteralBoilerplate(literals, elements); 353 default: 354 UNREACHABLE(); 355 return Handle<Object>::null(); 356 } 357} 358 359 360static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) { 361 HandleScope scope; 362 ASSERT(args.length() == 3); 363 // Copy the arguments. 364 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 365 CONVERT_SMI_CHECKED(literals_index, args[1]); 366 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); 367 368 Handle<Object> result = 369 CreateObjectLiteralBoilerplate(literals, constant_properties); 370 371 if (result.is_null()) return Failure::Exception(); 372 373 // Update the functions literal and return the boilerplate. 374 literals->set(literals_index, *result); 375 376 return *result; 377} 378 379 380static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { 381 // Takes a FixedArray of elements containing the literal elements of 382 // the array literal and produces JSArray with those elements. 383 // Additionally takes the literals array of the surrounding function 384 // which contains the context from which to get the Array function 385 // to use for creating the array literal. 386 HandleScope scope; 387 ASSERT(args.length() == 3); 388 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 389 CONVERT_SMI_CHECKED(literals_index, args[1]); 390 CONVERT_ARG_CHECKED(FixedArray, elements, 2); 391 392 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements); 393 if (object.is_null()) return Failure::Exception(); 394 395 // Update the functions literal and return the boilerplate. 396 literals->set(literals_index, *object); 397 return *object; 398} 399 400 401static Object* Runtime_CreateObjectLiteral(Arguments args) { 402 HandleScope scope; 403 ASSERT(args.length() == 3); 404 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 405 CONVERT_SMI_CHECKED(literals_index, args[1]); 406 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); 407 408 // Check if boilerplate exists. If not, create it first. 409 Handle<Object> boilerplate(literals->get(literals_index)); 410 if (*boilerplate == Heap::undefined_value()) { 411 boilerplate = CreateObjectLiteralBoilerplate(literals, constant_properties); 412 if (boilerplate.is_null()) return Failure::Exception(); 413 // Update the functions literal and return the boilerplate. 414 literals->set(literals_index, *boilerplate); 415 } 416 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); 417} 418 419 420static Object* Runtime_CreateObjectLiteralShallow(Arguments args) { 421 HandleScope scope; 422 ASSERT(args.length() == 3); 423 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 424 CONVERT_SMI_CHECKED(literals_index, args[1]); 425 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); 426 427 // Check if boilerplate exists. If not, create it first. 428 Handle<Object> boilerplate(literals->get(literals_index)); 429 if (*boilerplate == Heap::undefined_value()) { 430 boilerplate = CreateObjectLiteralBoilerplate(literals, constant_properties); 431 if (boilerplate.is_null()) return Failure::Exception(); 432 // Update the functions literal and return the boilerplate. 433 literals->set(literals_index, *boilerplate); 434 } 435 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); 436} 437 438 439static Object* Runtime_CreateArrayLiteral(Arguments args) { 440 HandleScope scope; 441 ASSERT(args.length() == 3); 442 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 443 CONVERT_SMI_CHECKED(literals_index, args[1]); 444 CONVERT_ARG_CHECKED(FixedArray, elements, 2); 445 446 // Check if boilerplate exists. If not, create it first. 447 Handle<Object> boilerplate(literals->get(literals_index)); 448 if (*boilerplate == Heap::undefined_value()) { 449 boilerplate = CreateArrayLiteralBoilerplate(literals, elements); 450 if (boilerplate.is_null()) return Failure::Exception(); 451 // Update the functions literal and return the boilerplate. 452 literals->set(literals_index, *boilerplate); 453 } 454 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); 455} 456 457 458static Object* Runtime_CreateArrayLiteralShallow(Arguments args) { 459 HandleScope scope; 460 ASSERT(args.length() == 3); 461 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 462 CONVERT_SMI_CHECKED(literals_index, args[1]); 463 CONVERT_ARG_CHECKED(FixedArray, elements, 2); 464 465 // Check if boilerplate exists. If not, create it first. 466 Handle<Object> boilerplate(literals->get(literals_index)); 467 if (*boilerplate == Heap::undefined_value()) { 468 boilerplate = CreateArrayLiteralBoilerplate(literals, elements); 469 if (boilerplate.is_null()) return Failure::Exception(); 470 // Update the functions literal and return the boilerplate. 471 literals->set(literals_index, *boilerplate); 472 } 473 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); 474} 475 476 477static Object* Runtime_CreateCatchExtensionObject(Arguments args) { 478 ASSERT(args.length() == 2); 479 CONVERT_CHECKED(String, key, args[0]); 480 Object* value = args[1]; 481 // Create a catch context extension object. 482 JSFunction* constructor = 483 Top::context()->global_context()->context_extension_function(); 484 Object* object = Heap::AllocateJSObject(constructor); 485 if (object->IsFailure()) return object; 486 // Assign the exception value to the catch variable and make sure 487 // that the catch variable is DontDelete. 488 value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE); 489 if (value->IsFailure()) return value; 490 return object; 491} 492 493 494static Object* Runtime_ClassOf(Arguments args) { 495 NoHandleAllocation ha; 496 ASSERT(args.length() == 1); 497 Object* obj = args[0]; 498 if (!obj->IsJSObject()) return Heap::null_value(); 499 return JSObject::cast(obj)->class_name(); 500} 501 502 503static Object* Runtime_IsInPrototypeChain(Arguments args) { 504 NoHandleAllocation ha; 505 ASSERT(args.length() == 2); 506 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). 507 Object* O = args[0]; 508 Object* V = args[1]; 509 while (true) { 510 Object* prototype = V->GetPrototype(); 511 if (prototype->IsNull()) return Heap::false_value(); 512 if (O == prototype) return Heap::true_value(); 513 V = prototype; 514 } 515} 516 517 518// Inserts an object as the hidden prototype of another object. 519static Object* Runtime_SetHiddenPrototype(Arguments args) { 520 NoHandleAllocation ha; 521 ASSERT(args.length() == 2); 522 CONVERT_CHECKED(JSObject, jsobject, args[0]); 523 CONVERT_CHECKED(JSObject, proto, args[1]); 524 525 // Sanity checks. The old prototype (that we are replacing) could 526 // theoretically be null, but if it is not null then check that we 527 // didn't already install a hidden prototype here. 528 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() || 529 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype()); 530 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype()); 531 532 // Allocate up front before we start altering state in case we get a GC. 533 Object* map_or_failure = proto->map()->CopyDropTransitions(); 534 if (map_or_failure->IsFailure()) return map_or_failure; 535 Map* new_proto_map = Map::cast(map_or_failure); 536 537 map_or_failure = jsobject->map()->CopyDropTransitions(); 538 if (map_or_failure->IsFailure()) return map_or_failure; 539 Map* new_map = Map::cast(map_or_failure); 540 541 // Set proto's prototype to be the old prototype of the object. 542 new_proto_map->set_prototype(jsobject->GetPrototype()); 543 proto->set_map(new_proto_map); 544 new_proto_map->set_is_hidden_prototype(); 545 546 // Set the object's prototype to proto. 547 new_map->set_prototype(proto); 548 jsobject->set_map(new_map); 549 550 return Heap::undefined_value(); 551} 552 553 554static Object* Runtime_IsConstructCall(Arguments args) { 555 NoHandleAllocation ha; 556 ASSERT(args.length() == 0); 557 JavaScriptFrameIterator it; 558 return Heap::ToBoolean(it.frame()->IsConstructor()); 559} 560 561 562// Recursively traverses hidden prototypes if property is not found 563static void GetOwnPropertyImplementation(JSObject* obj, 564 String* name, 565 LookupResult* result) { 566 obj->LocalLookupRealNamedProperty(name, result); 567 568 if (!result->IsProperty()) { 569 Object* proto = obj->GetPrototype(); 570 if (proto->IsJSObject() && 571 JSObject::cast(proto)->map()->is_hidden_prototype()) 572 GetOwnPropertyImplementation(JSObject::cast(proto), 573 name, result); 574 } 575} 576 577 578// Returns an array with the property description: 579// if args[1] is not a property on args[0] 580// returns undefined 581// if args[1] is a data property on args[0] 582// [false, value, Writeable, Enumerable, Configurable] 583// if args[1] is an accessor on args[0] 584// [true, GetFunction, SetFunction, Enumerable, Configurable] 585static Object* Runtime_GetOwnProperty(Arguments args) { 586 ASSERT(args.length() == 2); 587 HandleScope scope; 588 Handle<FixedArray> elms = Factory::NewFixedArray(5); 589 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms); 590 LookupResult result; 591 CONVERT_CHECKED(JSObject, obj, args[0]); 592 CONVERT_CHECKED(String, name, args[1]); 593 594 // Use recursive implementation to also traverse hidden prototypes 595 GetOwnPropertyImplementation(obj, name, &result); 596 597 if (!result.IsProperty()) 598 return Heap::undefined_value(); 599 600 if (result.type() == CALLBACKS) { 601 Object* structure = result.GetCallbackObject(); 602 if (structure->IsProxy()) { 603 // Property that is internally implemented as a callback. 604 Object* value = obj->GetPropertyWithCallback( 605 obj, structure, name, result.holder()); 606 elms->set(0, Heap::false_value()); 607 elms->set(1, value); 608 elms->set(2, Heap::ToBoolean(!result.IsReadOnly())); 609 } else if (structure->IsFixedArray()) { 610 // __defineGetter__/__defineSetter__ callback. 611 elms->set(0, Heap::true_value()); 612 elms->set(1, FixedArray::cast(structure)->get(0)); 613 elms->set(2, FixedArray::cast(structure)->get(1)); 614 } else { 615 // TODO(ricow): Handle API callbacks. 616 return Heap::undefined_value(); 617 } 618 } else { 619 elms->set(0, Heap::false_value()); 620 elms->set(1, result.GetLazyValue()); 621 elms->set(2, Heap::ToBoolean(!result.IsReadOnly())); 622 } 623 624 elms->set(3, Heap::ToBoolean(!result.IsDontEnum())); 625 elms->set(4, Heap::ToBoolean(!result.IsReadOnly())); 626 return *desc; 627} 628 629 630static Object* Runtime_IsExtensible(Arguments args) { 631 ASSERT(args.length() == 1); 632 CONVERT_CHECKED(JSObject, obj, args[0]); 633 return obj->map()->is_extensible() ? Heap::true_value() 634 : Heap::false_value(); 635} 636 637 638static Object* Runtime_RegExpCompile(Arguments args) { 639 HandleScope scope; 640 ASSERT(args.length() == 3); 641 CONVERT_ARG_CHECKED(JSRegExp, re, 0); 642 CONVERT_ARG_CHECKED(String, pattern, 1); 643 CONVERT_ARG_CHECKED(String, flags, 2); 644 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags); 645 if (result.is_null()) return Failure::Exception(); 646 return *result; 647} 648 649 650static Object* Runtime_CreateApiFunction(Arguments args) { 651 HandleScope scope; 652 ASSERT(args.length() == 1); 653 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0); 654 return *Factory::CreateApiFunction(data); 655} 656 657 658static Object* Runtime_IsTemplate(Arguments args) { 659 ASSERT(args.length() == 1); 660 Object* arg = args[0]; 661 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); 662 return Heap::ToBoolean(result); 663} 664 665 666static Object* Runtime_GetTemplateField(Arguments args) { 667 ASSERT(args.length() == 2); 668 CONVERT_CHECKED(HeapObject, templ, args[0]); 669 CONVERT_CHECKED(Smi, field, args[1]); 670 int index = field->value(); 671 int offset = index * kPointerSize + HeapObject::kHeaderSize; 672 InstanceType type = templ->map()->instance_type(); 673 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || 674 type == OBJECT_TEMPLATE_INFO_TYPE); 675 RUNTIME_ASSERT(offset > 0); 676 if (type == FUNCTION_TEMPLATE_INFO_TYPE) { 677 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); 678 } else { 679 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); 680 } 681 return *HeapObject::RawField(templ, offset); 682} 683 684 685static Object* Runtime_DisableAccessChecks(Arguments args) { 686 ASSERT(args.length() == 1); 687 CONVERT_CHECKED(HeapObject, object, args[0]); 688 Map* old_map = object->map(); 689 bool needs_access_checks = old_map->is_access_check_needed(); 690 if (needs_access_checks) { 691 // Copy map so it won't interfere constructor's initial map. 692 Object* new_map = old_map->CopyDropTransitions(); 693 if (new_map->IsFailure()) return new_map; 694 695 Map::cast(new_map)->set_is_access_check_needed(false); 696 object->set_map(Map::cast(new_map)); 697 } 698 return needs_access_checks ? Heap::true_value() : Heap::false_value(); 699} 700 701 702static Object* Runtime_EnableAccessChecks(Arguments args) { 703 ASSERT(args.length() == 1); 704 CONVERT_CHECKED(HeapObject, object, args[0]); 705 Map* old_map = object->map(); 706 if (!old_map->is_access_check_needed()) { 707 // Copy map so it won't interfere constructor's initial map. 708 Object* new_map = old_map->CopyDropTransitions(); 709 if (new_map->IsFailure()) return new_map; 710 711 Map::cast(new_map)->set_is_access_check_needed(true); 712 object->set_map(Map::cast(new_map)); 713 } 714 return Heap::undefined_value(); 715} 716 717 718static Object* ThrowRedeclarationError(const char* type, Handle<String> name) { 719 HandleScope scope; 720 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type)); 721 Handle<Object> args[2] = { type_handle, name }; 722 Handle<Object> error = 723 Factory::NewTypeError("redeclaration", HandleVector(args, 2)); 724 return Top::Throw(*error); 725} 726 727 728static Object* Runtime_DeclareGlobals(Arguments args) { 729 HandleScope scope; 730 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global()); 731 732 Handle<Context> context = args.at<Context>(0); 733 CONVERT_ARG_CHECKED(FixedArray, pairs, 1); 734 bool is_eval = Smi::cast(args[2])->value() == 1; 735 736 // Compute the property attributes. According to ECMA-262, section 737 // 13, page 71, the property must be read-only and 738 // non-deletable. However, neither SpiderMonkey nor KJS creates the 739 // property as read-only, so we don't either. 740 PropertyAttributes base = is_eval ? NONE : DONT_DELETE; 741 742 // Traverse the name/value pairs and set the properties. 743 int length = pairs->length(); 744 for (int i = 0; i < length; i += 2) { 745 HandleScope scope; 746 Handle<String> name(String::cast(pairs->get(i))); 747 Handle<Object> value(pairs->get(i + 1)); 748 749 // We have to declare a global const property. To capture we only 750 // assign to it when evaluating the assignment for "const x = 751 // <expr>" the initial value is the hole. 752 bool is_const_property = value->IsTheHole(); 753 754 if (value->IsUndefined() || is_const_property) { 755 // Lookup the property in the global object, and don't set the 756 // value of the variable if the property is already there. 757 LookupResult lookup; 758 global->Lookup(*name, &lookup); 759 if (lookup.IsProperty()) { 760 // Determine if the property is local by comparing the holder 761 // against the global object. The information will be used to 762 // avoid throwing re-declaration errors when declaring 763 // variables or constants that exist in the prototype chain. 764 bool is_local = (*global == lookup.holder()); 765 // Get the property attributes and determine if the property is 766 // read-only. 767 PropertyAttributes attributes = global->GetPropertyAttribute(*name); 768 bool is_read_only = (attributes & READ_ONLY) != 0; 769 if (lookup.type() == INTERCEPTOR) { 770 // If the interceptor says the property is there, we 771 // just return undefined without overwriting the property. 772 // Otherwise, we continue to setting the property. 773 if (attributes != ABSENT) { 774 // Check if the existing property conflicts with regards to const. 775 if (is_local && (is_read_only || is_const_property)) { 776 const char* type = (is_read_only) ? "const" : "var"; 777 return ThrowRedeclarationError(type, name); 778 }; 779 // The property already exists without conflicting: Go to 780 // the next declaration. 781 continue; 782 } 783 // Fall-through and introduce the absent property by using 784 // SetProperty. 785 } else { 786 if (is_local && (is_read_only || is_const_property)) { 787 const char* type = (is_read_only) ? "const" : "var"; 788 return ThrowRedeclarationError(type, name); 789 } 790 // The property already exists without conflicting: Go to 791 // the next declaration. 792 continue; 793 } 794 } 795 } else { 796 // Copy the function and update its context. Use it as value. 797 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value); 798 Handle<JSFunction> function = 799 Factory::NewFunctionFromBoilerplate(boilerplate, context, TENURED); 800 value = function; 801 } 802 803 LookupResult lookup; 804 global->LocalLookup(*name, &lookup); 805 806 PropertyAttributes attributes = is_const_property 807 ? static_cast<PropertyAttributes>(base | READ_ONLY) 808 : base; 809 810 if (lookup.IsProperty()) { 811 // There's a local property that we need to overwrite because 812 // we're either declaring a function or there's an interceptor 813 // that claims the property is absent. 814 815 // Check for conflicting re-declarations. We cannot have 816 // conflicting types in case of intercepted properties because 817 // they are absent. 818 if (lookup.type() != INTERCEPTOR && 819 (lookup.IsReadOnly() || is_const_property)) { 820 const char* type = (lookup.IsReadOnly()) ? "const" : "var"; 821 return ThrowRedeclarationError(type, name); 822 } 823 SetProperty(global, name, value, attributes); 824 } else { 825 // If a property with this name does not already exist on the 826 // global object add the property locally. We take special 827 // precautions to always add it as a local property even in case 828 // of callbacks in the prototype chain (this rules out using 829 // SetProperty). Also, we must use the handle-based version to 830 // avoid GC issues. 831 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes); 832 } 833 } 834 835 return Heap::undefined_value(); 836} 837 838 839static Object* Runtime_DeclareContextSlot(Arguments args) { 840 HandleScope scope; 841 ASSERT(args.length() == 4); 842 843 CONVERT_ARG_CHECKED(Context, context, 0); 844 Handle<String> name(String::cast(args[1])); 845 PropertyAttributes mode = 846 static_cast<PropertyAttributes>(Smi::cast(args[2])->value()); 847 ASSERT(mode == READ_ONLY || mode == NONE); 848 Handle<Object> initial_value(args[3]); 849 850 // Declarations are always done in the function context. 851 context = Handle<Context>(context->fcontext()); 852 853 int index; 854 PropertyAttributes attributes; 855 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 856 Handle<Object> holder = 857 context->Lookup(name, flags, &index, &attributes); 858 859 if (attributes != ABSENT) { 860 // The name was declared before; check for conflicting 861 // re-declarations: This is similar to the code in parser.cc in 862 // the AstBuildingParser::Declare function. 863 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { 864 // Functions are not read-only. 865 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); 866 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; 867 return ThrowRedeclarationError(type, name); 868 } 869 870 // Initialize it if necessary. 871 if (*initial_value != NULL) { 872 if (index >= 0) { 873 // The variable or constant context slot should always be in 874 // the function context or the arguments object. 875 if (holder->IsContext()) { 876 ASSERT(holder.is_identical_to(context)); 877 if (((attributes & READ_ONLY) == 0) || 878 context->get(index)->IsTheHole()) { 879 context->set(index, *initial_value); 880 } 881 } else { 882 Handle<JSObject>::cast(holder)->SetElement(index, *initial_value); 883 } 884 } else { 885 // Slow case: The property is not in the FixedArray part of the context. 886 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); 887 SetProperty(context_ext, name, initial_value, mode); 888 } 889 } 890 891 } else { 892 // The property is not in the function context. It needs to be 893 // "declared" in the function context's extension context, or in the 894 // global context. 895 Handle<JSObject> context_ext; 896 if (context->has_extension()) { 897 // The function context's extension context exists - use it. 898 context_ext = Handle<JSObject>(context->extension()); 899 } else { 900 // The function context's extension context does not exists - allocate 901 // it. 902 context_ext = Factory::NewJSObject(Top::context_extension_function()); 903 // And store it in the extension slot. 904 context->set_extension(*context_ext); 905 } 906 ASSERT(*context_ext != NULL); 907 908 // Declare the property by setting it to the initial value if provided, 909 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for 910 // constant declarations). 911 ASSERT(!context_ext->HasLocalProperty(*name)); 912 Handle<Object> value(Heap::undefined_value()); 913 if (*initial_value != NULL) value = initial_value; 914 SetProperty(context_ext, name, value, mode); 915 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode); 916 } 917 918 return Heap::undefined_value(); 919} 920 921 922static Object* Runtime_InitializeVarGlobal(Arguments args) { 923 NoHandleAllocation nha; 924 925 // Determine if we need to assign to the variable if it already 926 // exists (based on the number of arguments). 927 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 928 bool assign = args.length() == 2; 929 930 CONVERT_ARG_CHECKED(String, name, 0); 931 GlobalObject* global = Top::context()->global(); 932 933 // According to ECMA-262, section 12.2, page 62, the property must 934 // not be deletable. 935 PropertyAttributes attributes = DONT_DELETE; 936 937 // Lookup the property locally in the global object. If it isn't 938 // there, there is a property with this name in the prototype chain. 939 // We follow Safari and Firefox behavior and only set the property 940 // locally if there is an explicit initialization value that we have 941 // to assign to the property. When adding the property we take 942 // special precautions to always add it as a local property even in 943 // case of callbacks in the prototype chain (this rules out using 944 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for 945 // this. 946 // Note that objects can have hidden prototypes, so we need to traverse 947 // the whole chain of hidden prototypes to do a 'local' lookup. 948 JSObject* real_holder = global; 949 LookupResult lookup; 950 while (true) { 951 real_holder->LocalLookup(*name, &lookup); 952 if (lookup.IsProperty()) { 953 // Determine if this is a redeclaration of something read-only. 954 if (lookup.IsReadOnly()) { 955 // If we found readonly property on one of hidden prototypes, 956 // just shadow it. 957 if (real_holder != Top::context()->global()) break; 958 return ThrowRedeclarationError("const", name); 959 } 960 961 // Determine if this is a redeclaration of an intercepted read-only 962 // property and figure out if the property exists at all. 963 bool found = true; 964 PropertyType type = lookup.type(); 965 if (type == INTERCEPTOR) { 966 HandleScope handle_scope; 967 Handle<JSObject> holder(real_holder); 968 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name); 969 real_holder = *holder; 970 if (intercepted == ABSENT) { 971 // The interceptor claims the property isn't there. We need to 972 // make sure to introduce it. 973 found = false; 974 } else if ((intercepted & READ_ONLY) != 0) { 975 // The property is present, but read-only. Since we're trying to 976 // overwrite it with a variable declaration we must throw a 977 // re-declaration error. However if we found readonly property 978 // on one of hidden prototypes, just shadow it. 979 if (real_holder != Top::context()->global()) break; 980 return ThrowRedeclarationError("const", name); 981 } 982 } 983 984 if (found && !assign) { 985 // The global property is there and we're not assigning any value 986 // to it. Just return. 987 return Heap::undefined_value(); 988 } 989 990 // Assign the value (or undefined) to the property. 991 Object* value = (assign) ? args[1] : Heap::undefined_value(); 992 return real_holder->SetProperty(&lookup, *name, value, attributes); 993 } 994 995 Object* proto = real_holder->GetPrototype(); 996 if (!proto->IsJSObject()) 997 break; 998 999 if (!JSObject::cast(proto)->map()->is_hidden_prototype()) 1000 break; 1001 1002 real_holder = JSObject::cast(proto); 1003 } 1004 1005 global = Top::context()->global(); 1006 if (assign) { 1007 return global->IgnoreAttributesAndSetLocalProperty(*name, 1008 args[1], 1009 attributes); 1010 } 1011 return Heap::undefined_value(); 1012} 1013 1014 1015static Object* Runtime_InitializeConstGlobal(Arguments args) { 1016 // All constants are declared with an initial value. The name 1017 // of the constant is the first argument and the initial value 1018 // is the second. 1019 RUNTIME_ASSERT(args.length() == 2); 1020 CONVERT_ARG_CHECKED(String, name, 0); 1021 Handle<Object> value = args.at<Object>(1); 1022 1023 // Get the current global object from top. 1024 GlobalObject* global = Top::context()->global(); 1025 1026 // According to ECMA-262, section 12.2, page 62, the property must 1027 // not be deletable. Since it's a const, it must be READ_ONLY too. 1028 PropertyAttributes attributes = 1029 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); 1030 1031 // Lookup the property locally in the global object. If it isn't 1032 // there, we add the property and take special precautions to always 1033 // add it as a local property even in case of callbacks in the 1034 // prototype chain (this rules out using SetProperty). 1035 // We use IgnoreAttributesAndSetLocalProperty instead 1036 LookupResult lookup; 1037 global->LocalLookup(*name, &lookup); 1038 if (!lookup.IsProperty()) { 1039 return global->IgnoreAttributesAndSetLocalProperty(*name, 1040 *value, 1041 attributes); 1042 } 1043 1044 // Determine if this is a redeclaration of something not 1045 // read-only. In case the result is hidden behind an interceptor we 1046 // need to ask it for the property attributes. 1047 if (!lookup.IsReadOnly()) { 1048 if (lookup.type() != INTERCEPTOR) { 1049 return ThrowRedeclarationError("var", name); 1050 } 1051 1052 PropertyAttributes intercepted = global->GetPropertyAttribute(*name); 1053 1054 // Throw re-declaration error if the intercepted property is present 1055 // but not read-only. 1056 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { 1057 return ThrowRedeclarationError("var", name); 1058 } 1059 1060 // Restore global object from context (in case of GC) and continue 1061 // with setting the value because the property is either absent or 1062 // read-only. We also have to do redo the lookup. 1063 global = Top::context()->global(); 1064 1065 // BUG 1213579: Handle the case where we have to set a read-only 1066 // property through an interceptor and only do it if it's 1067 // uninitialized, e.g. the hole. Nirk... 1068 global->SetProperty(*name, *value, attributes); 1069 return *value; 1070 } 1071 1072 // Set the value, but only we're assigning the initial value to a 1073 // constant. For now, we determine this by checking if the 1074 // current value is the hole. 1075 PropertyType type = lookup.type(); 1076 if (type == FIELD) { 1077 FixedArray* properties = global->properties(); 1078 int index = lookup.GetFieldIndex(); 1079 if (properties->get(index)->IsTheHole()) { 1080 properties->set(index, *value); 1081 } 1082 } else if (type == NORMAL) { 1083 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) { 1084 global->SetNormalizedProperty(&lookup, *value); 1085 } 1086 } else { 1087 // Ignore re-initialization of constants that have already been 1088 // assigned a function value. 1089 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION); 1090 } 1091 1092 // Use the set value as the result of the operation. 1093 return *value; 1094} 1095 1096 1097static Object* Runtime_InitializeConstContextSlot(Arguments args) { 1098 HandleScope scope; 1099 ASSERT(args.length() == 3); 1100 1101 Handle<Object> value(args[0]); 1102 ASSERT(!value->IsTheHole()); 1103 CONVERT_ARG_CHECKED(Context, context, 1); 1104 Handle<String> name(String::cast(args[2])); 1105 1106 // Initializations are always done in the function context. 1107 context = Handle<Context>(context->fcontext()); 1108 1109 int index; 1110 PropertyAttributes attributes; 1111 ContextLookupFlags flags = FOLLOW_CHAINS; 1112 Handle<Object> holder = 1113 context->Lookup(name, flags, &index, &attributes); 1114 1115 // In most situations, the property introduced by the const 1116 // declaration should be present in the context extension object. 1117 // However, because declaration and initialization are separate, the 1118 // property might have been deleted (if it was introduced by eval) 1119 // before we reach the initialization point. 1120 // 1121 // Example: 1122 // 1123 // function f() { eval("delete x; const x;"); } 1124 // 1125 // In that case, the initialization behaves like a normal assignment 1126 // to property 'x'. 1127 if (index >= 0) { 1128 // Property was found in a context. 1129 if (holder->IsContext()) { 1130 // The holder cannot be the function context. If it is, there 1131 // should have been a const redeclaration error when declaring 1132 // the const property. 1133 ASSERT(!holder.is_identical_to(context)); 1134 if ((attributes & READ_ONLY) == 0) { 1135 Handle<Context>::cast(holder)->set(index, *value); 1136 } 1137 } else { 1138 // The holder is an arguments object. 1139 ASSERT((attributes & READ_ONLY) == 0); 1140 Handle<JSObject>::cast(holder)->SetElement(index, *value); 1141 } 1142 return *value; 1143 } 1144 1145 // The property could not be found, we introduce it in the global 1146 // context. 1147 if (attributes == ABSENT) { 1148 Handle<JSObject> global = Handle<JSObject>(Top::context()->global()); 1149 SetProperty(global, name, value, NONE); 1150 return *value; 1151 } 1152 1153 // The property was present in a context extension object. 1154 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); 1155 1156 if (*context_ext == context->extension()) { 1157 // This is the property that was introduced by the const 1158 // declaration. Set it if it hasn't been set before. NOTE: We 1159 // cannot use GetProperty() to get the current value as it 1160 // 'unholes' the value. 1161 LookupResult lookup; 1162 context_ext->LocalLookupRealNamedProperty(*name, &lookup); 1163 ASSERT(lookup.IsProperty()); // the property was declared 1164 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only 1165 1166 PropertyType type = lookup.type(); 1167 if (type == FIELD) { 1168 FixedArray* properties = context_ext->properties(); 1169 int index = lookup.GetFieldIndex(); 1170 if (properties->get(index)->IsTheHole()) { 1171 properties->set(index, *value); 1172 } 1173 } else if (type == NORMAL) { 1174 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) { 1175 context_ext->SetNormalizedProperty(&lookup, *value); 1176 } 1177 } else { 1178 // We should not reach here. Any real, named property should be 1179 // either a field or a dictionary slot. 1180 UNREACHABLE(); 1181 } 1182 } else { 1183 // The property was found in a different context extension object. 1184 // Set it if it is not a read-only property. 1185 if ((attributes & READ_ONLY) == 0) { 1186 Handle<Object> set = SetProperty(context_ext, name, value, attributes); 1187 // Setting a property might throw an exception. Exceptions 1188 // are converted to empty handles in handle operations. We 1189 // need to convert back to exceptions here. 1190 if (set.is_null()) { 1191 ASSERT(Top::has_pending_exception()); 1192 return Failure::Exception(); 1193 } 1194 } 1195 } 1196 1197 return *value; 1198} 1199 1200 1201static Object* Runtime_OptimizeObjectForAddingMultipleProperties( 1202 Arguments args) { 1203 HandleScope scope; 1204 ASSERT(args.length() == 2); 1205 CONVERT_ARG_CHECKED(JSObject, object, 0); 1206 CONVERT_SMI_CHECKED(properties, args[1]); 1207 if (object->HasFastProperties()) { 1208 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); 1209 } 1210 return *object; 1211} 1212 1213 1214static Object* Runtime_TransformToFastProperties(Arguments args) { 1215 HandleScope scope; 1216 ASSERT(args.length() == 1); 1217 CONVERT_ARG_CHECKED(JSObject, object, 0); 1218 if (!object->HasFastProperties() && !object->IsGlobalObject()) { 1219 TransformToFastProperties(object, 0); 1220 } 1221 return *object; 1222} 1223 1224 1225static Object* Runtime_RegExpExec(Arguments args) { 1226 HandleScope scope; 1227 ASSERT(args.length() == 4); 1228 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); 1229 CONVERT_ARG_CHECKED(String, subject, 1); 1230 // Due to the way the JS calls are constructed this must be less than the 1231 // length of a string, i.e. it is always a Smi. We check anyway for security. 1232 CONVERT_SMI_CHECKED(index, args[2]); 1233 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3); 1234 RUNTIME_ASSERT(last_match_info->HasFastElements()); 1235 RUNTIME_ASSERT(index >= 0); 1236 RUNTIME_ASSERT(index <= subject->length()); 1237 Counters::regexp_entry_runtime.Increment(); 1238 Handle<Object> result = RegExpImpl::Exec(regexp, 1239 subject, 1240 index, 1241 last_match_info); 1242 if (result.is_null()) return Failure::Exception(); 1243 return *result; 1244} 1245 1246 1247static Object* Runtime_MaterializeRegExpLiteral(Arguments args) { 1248 HandleScope scope; 1249 ASSERT(args.length() == 4); 1250 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 1251 int index = Smi::cast(args[1])->value(); 1252 Handle<String> pattern = args.at<String>(2); 1253 Handle<String> flags = args.at<String>(3); 1254 1255 // Get the RegExp function from the context in the literals array. 1256 // This is the RegExp function from the context in which the 1257 // function was created. We do not use the RegExp function from the 1258 // current global context because this might be the RegExp function 1259 // from another context which we should not have access to. 1260 Handle<JSFunction> constructor = 1261 Handle<JSFunction>( 1262 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function()); 1263 // Compute the regular expression literal. 1264 bool has_pending_exception; 1265 Handle<Object> regexp = 1266 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags, 1267 &has_pending_exception); 1268 if (has_pending_exception) { 1269 ASSERT(Top::has_pending_exception()); 1270 return Failure::Exception(); 1271 } 1272 literals->set(index, *regexp); 1273 return *regexp; 1274} 1275 1276 1277static Object* Runtime_FunctionGetName(Arguments args) { 1278 NoHandleAllocation ha; 1279 ASSERT(args.length() == 1); 1280 1281 CONVERT_CHECKED(JSFunction, f, args[0]); 1282 return f->shared()->name(); 1283} 1284 1285 1286static Object* Runtime_FunctionSetName(Arguments args) { 1287 NoHandleAllocation ha; 1288 ASSERT(args.length() == 2); 1289 1290 CONVERT_CHECKED(JSFunction, f, args[0]); 1291 CONVERT_CHECKED(String, name, args[1]); 1292 f->shared()->set_name(name); 1293 return Heap::undefined_value(); 1294} 1295 1296 1297static Object* Runtime_FunctionGetScript(Arguments args) { 1298 HandleScope scope; 1299 ASSERT(args.length() == 1); 1300 1301 CONVERT_CHECKED(JSFunction, fun, args[0]); 1302 Handle<Object> script = Handle<Object>(fun->shared()->script()); 1303 if (!script->IsScript()) return Heap::undefined_value(); 1304 1305 return *GetScriptWrapper(Handle<Script>::cast(script)); 1306} 1307 1308 1309static Object* Runtime_FunctionGetSourceCode(Arguments args) { 1310 NoHandleAllocation ha; 1311 ASSERT(args.length() == 1); 1312 1313 CONVERT_CHECKED(JSFunction, f, args[0]); 1314 return f->shared()->GetSourceCode(); 1315} 1316 1317 1318static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) { 1319 NoHandleAllocation ha; 1320 ASSERT(args.length() == 1); 1321 1322 CONVERT_CHECKED(JSFunction, fun, args[0]); 1323 int pos = fun->shared()->start_position(); 1324 return Smi::FromInt(pos); 1325} 1326 1327 1328static Object* Runtime_FunctionGetPositionForOffset(Arguments args) { 1329 ASSERT(args.length() == 2); 1330 1331 CONVERT_CHECKED(JSFunction, fun, args[0]); 1332 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); 1333 1334 Code* code = fun->code(); 1335 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); 1336 1337 Address pc = code->address() + offset; 1338 return Smi::FromInt(fun->code()->SourcePosition(pc)); 1339} 1340 1341 1342 1343static Object* Runtime_FunctionSetInstanceClassName(Arguments args) { 1344 NoHandleAllocation ha; 1345 ASSERT(args.length() == 2); 1346 1347 CONVERT_CHECKED(JSFunction, fun, args[0]); 1348 CONVERT_CHECKED(String, name, args[1]); 1349 fun->SetInstanceClassName(name); 1350 return Heap::undefined_value(); 1351} 1352 1353 1354static Object* Runtime_FunctionSetLength(Arguments args) { 1355 NoHandleAllocation ha; 1356 ASSERT(args.length() == 2); 1357 1358 CONVERT_CHECKED(JSFunction, fun, args[0]); 1359 CONVERT_CHECKED(Smi, length, args[1]); 1360 fun->shared()->set_length(length->value()); 1361 return length; 1362} 1363 1364 1365static Object* Runtime_FunctionSetPrototype(Arguments args) { 1366 NoHandleAllocation ha; 1367 ASSERT(args.length() == 2); 1368 1369 CONVERT_CHECKED(JSFunction, fun, args[0]); 1370 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL); 1371 if (obj->IsFailure()) return obj; 1372 return args[0]; // return TOS 1373} 1374 1375 1376static Object* Runtime_FunctionIsAPIFunction(Arguments args) { 1377 NoHandleAllocation ha; 1378 ASSERT(args.length() == 1); 1379 1380 CONVERT_CHECKED(JSFunction, f, args[0]); 1381 // The function_data field of the shared function info is used exclusively by 1382 // the API. 1383 return !f->shared()->function_data()->IsUndefined() ? Heap::true_value() 1384 : Heap::false_value(); 1385} 1386 1387static Object* Runtime_FunctionIsBuiltin(Arguments args) { 1388 NoHandleAllocation ha; 1389 ASSERT(args.length() == 1); 1390 1391 CONVERT_CHECKED(JSFunction, f, args[0]); 1392 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value(); 1393} 1394 1395 1396static Object* Runtime_SetCode(Arguments args) { 1397 HandleScope scope; 1398 ASSERT(args.length() == 2); 1399 1400 CONVERT_ARG_CHECKED(JSFunction, target, 0); 1401 Handle<Object> code = args.at<Object>(1); 1402 1403 Handle<Context> context(target->context()); 1404 1405 if (!code->IsNull()) { 1406 RUNTIME_ASSERT(code->IsJSFunction()); 1407 Handle<JSFunction> fun = Handle<JSFunction>::cast(code); 1408 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties()); 1409 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) { 1410 return Failure::Exception(); 1411 } 1412 // Set the code, formal parameter count, and the length of the target 1413 // function. 1414 target->set_code(fun->code()); 1415 target->shared()->set_length(fun->shared()->length()); 1416 target->shared()->set_formal_parameter_count( 1417 fun->shared()->formal_parameter_count()); 1418 // Set the source code of the target function to undefined. 1419 // SetCode is only used for built-in constructors like String, 1420 // Array, and Object, and some web code 1421 // doesn't like seeing source code for constructors. 1422 target->shared()->set_script(Heap::undefined_value()); 1423 // Clear the optimization hints related to the compiled code as these are no 1424 // longer valid when the code is overwritten. 1425 target->shared()->ClearThisPropertyAssignmentsInfo(); 1426 context = Handle<Context>(fun->context()); 1427 1428 // Make sure we get a fresh copy of the literal vector to avoid 1429 // cross context contamination. 1430 int number_of_literals = fun->NumberOfLiterals(); 1431 Handle<FixedArray> literals = 1432 Factory::NewFixedArray(number_of_literals, TENURED); 1433 if (number_of_literals > 0) { 1434 // Insert the object, regexp and array functions in the literals 1435 // array prefix. These are the functions that will be used when 1436 // creating object, regexp and array literals. 1437 literals->set(JSFunction::kLiteralGlobalContextIndex, 1438 context->global_context()); 1439 } 1440 target->set_literals(*literals, SKIP_WRITE_BARRIER); 1441 } 1442 1443 target->set_context(*context); 1444 return *target; 1445} 1446 1447 1448static Object* CharCodeAt(String* subject, Object* index) { 1449 uint32_t i = 0; 1450 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); 1451 // Flatten the string. If someone wants to get a char at an index 1452 // in a cons string, it is likely that more indices will be 1453 // accessed. 1454 Object* flat = subject->TryFlatten(); 1455 if (flat->IsFailure()) return flat; 1456 subject = String::cast(flat); 1457 if (i >= static_cast<uint32_t>(subject->length())) { 1458 return Heap::nan_value(); 1459 } 1460 return Smi::FromInt(subject->Get(i)); 1461} 1462 1463 1464static Object* CharFromCode(Object* char_code) { 1465 uint32_t code; 1466 if (Array::IndexFromObject(char_code, &code)) { 1467 if (code <= 0xffff) { 1468 return Heap::LookupSingleCharacterStringFromCode(code); 1469 } 1470 } 1471 return Heap::empty_string(); 1472} 1473 1474 1475static Object* Runtime_StringCharCodeAt(Arguments args) { 1476 NoHandleAllocation ha; 1477 ASSERT(args.length() == 2); 1478 1479 CONVERT_CHECKED(String, subject, args[0]); 1480 Object* index = args[1]; 1481 return CharCodeAt(subject, index); 1482} 1483 1484 1485static Object* Runtime_StringCharAt(Arguments args) { 1486 NoHandleAllocation ha; 1487 ASSERT(args.length() == 2); 1488 1489 CONVERT_CHECKED(String, subject, args[0]); 1490 Object* index = args[1]; 1491 Object* code = CharCodeAt(subject, index); 1492 if (code == Heap::nan_value()) { 1493 return Heap::undefined_value(); 1494 } 1495 return CharFromCode(code); 1496} 1497 1498 1499static Object* Runtime_CharFromCode(Arguments args) { 1500 NoHandleAllocation ha; 1501 ASSERT(args.length() == 1); 1502 return CharFromCode(args[0]); 1503} 1504 1505// Forward declarations. 1506static const int kStringBuilderConcatHelperLengthBits = 11; 1507static const int kStringBuilderConcatHelperPositionBits = 19; 1508 1509template <typename schar> 1510static inline void StringBuilderConcatHelper(String*, 1511 schar*, 1512 FixedArray*, 1513 int); 1514 1515typedef BitField<int, 0, 11> StringBuilderSubstringLength; 1516typedef BitField<int, 11, 19> StringBuilderSubstringPosition; 1517 1518class ReplacementStringBuilder { 1519 public: 1520 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) 1521 : subject_(subject), 1522 parts_(Factory::NewFixedArray(estimated_part_count)), 1523 part_count_(0), 1524 character_count_(0), 1525 is_ascii_(subject->IsAsciiRepresentation()) { 1526 // Require a non-zero initial size. Ensures that doubling the size to 1527 // extend the array will work. 1528 ASSERT(estimated_part_count > 0); 1529 } 1530 1531 void EnsureCapacity(int elements) { 1532 int length = parts_->length(); 1533 int required_length = part_count_ + elements; 1534 if (length < required_length) { 1535 int new_length = length; 1536 do { 1537 new_length *= 2; 1538 } while (new_length < required_length); 1539 Handle<FixedArray> extended_array = 1540 Factory::NewFixedArray(new_length); 1541 parts_->CopyTo(0, *extended_array, 0, part_count_); 1542 parts_ = extended_array; 1543 } 1544 } 1545 1546 void AddSubjectSlice(int from, int to) { 1547 ASSERT(from >= 0); 1548 int length = to - from; 1549 ASSERT(length > 0); 1550 // Can we encode the slice in 11 bits for length and 19 bits for 1551 // start position - as used by StringBuilderConcatHelper? 1552 if (StringBuilderSubstringLength::is_valid(length) && 1553 StringBuilderSubstringPosition::is_valid(from)) { 1554 int encoded_slice = StringBuilderSubstringLength::encode(length) | 1555 StringBuilderSubstringPosition::encode(from); 1556 AddElement(Smi::FromInt(encoded_slice)); 1557 } else { 1558 // Otherwise encode as two smis. 1559 AddElement(Smi::FromInt(-length)); 1560 AddElement(Smi::FromInt(from)); 1561 } 1562 IncrementCharacterCount(length); 1563 } 1564 1565 1566 void AddString(Handle<String> string) { 1567 int length = string->length(); 1568 ASSERT(length > 0); 1569 AddElement(*string); 1570 if (!string->IsAsciiRepresentation()) { 1571 is_ascii_ = false; 1572 } 1573 IncrementCharacterCount(length); 1574 } 1575 1576 1577 Handle<String> ToString() { 1578 if (part_count_ == 0) { 1579 return Factory::empty_string(); 1580 } 1581 1582 Handle<String> joined_string; 1583 if (is_ascii_) { 1584 joined_string = NewRawAsciiString(character_count_); 1585 AssertNoAllocation no_alloc; 1586 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); 1587 char* char_buffer = seq->GetChars(); 1588 StringBuilderConcatHelper(*subject_, 1589 char_buffer, 1590 *parts_, 1591 part_count_); 1592 } else { 1593 // Non-ASCII. 1594 joined_string = NewRawTwoByteString(character_count_); 1595 AssertNoAllocation no_alloc; 1596 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); 1597 uc16* char_buffer = seq->GetChars(); 1598 StringBuilderConcatHelper(*subject_, 1599 char_buffer, 1600 *parts_, 1601 part_count_); 1602 } 1603 return joined_string; 1604 } 1605 1606 1607 void IncrementCharacterCount(int by) { 1608 if (character_count_ > String::kMaxLength - by) { 1609 V8::FatalProcessOutOfMemory("String.replace result too large."); 1610 } 1611 character_count_ += by; 1612 } 1613 1614 private: 1615 1616 Handle<String> NewRawAsciiString(int size) { 1617 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String); 1618 } 1619 1620 1621 Handle<String> NewRawTwoByteString(int size) { 1622 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String); 1623 } 1624 1625 1626 void AddElement(Object* element) { 1627 ASSERT(element->IsSmi() || element->IsString()); 1628 ASSERT(parts_->length() > part_count_); 1629 parts_->set(part_count_, element); 1630 part_count_++; 1631 } 1632 1633 Handle<String> subject_; 1634 Handle<FixedArray> parts_; 1635 int part_count_; 1636 int character_count_; 1637 bool is_ascii_; 1638}; 1639 1640 1641class CompiledReplacement { 1642 public: 1643 CompiledReplacement() 1644 : parts_(1), replacement_substrings_(0) {} 1645 1646 void Compile(Handle<String> replacement, 1647 int capture_count, 1648 int subject_length); 1649 1650 void Apply(ReplacementStringBuilder* builder, 1651 int match_from, 1652 int match_to, 1653 Handle<JSArray> last_match_info); 1654 1655 // Number of distinct parts of the replacement pattern. 1656 int parts() { 1657 return parts_.length(); 1658 } 1659 private: 1660 enum PartType { 1661 SUBJECT_PREFIX = 1, 1662 SUBJECT_SUFFIX, 1663 SUBJECT_CAPTURE, 1664 REPLACEMENT_SUBSTRING, 1665 REPLACEMENT_STRING, 1666 1667 NUMBER_OF_PART_TYPES 1668 }; 1669 1670 struct ReplacementPart { 1671 static inline ReplacementPart SubjectMatch() { 1672 return ReplacementPart(SUBJECT_CAPTURE, 0); 1673 } 1674 static inline ReplacementPart SubjectCapture(int capture_index) { 1675 return ReplacementPart(SUBJECT_CAPTURE, capture_index); 1676 } 1677 static inline ReplacementPart SubjectPrefix() { 1678 return ReplacementPart(SUBJECT_PREFIX, 0); 1679 } 1680 static inline ReplacementPart SubjectSuffix(int subject_length) { 1681 return ReplacementPart(SUBJECT_SUFFIX, subject_length); 1682 } 1683 static inline ReplacementPart ReplacementString() { 1684 return ReplacementPart(REPLACEMENT_STRING, 0); 1685 } 1686 static inline ReplacementPart ReplacementSubString(int from, int to) { 1687 ASSERT(from >= 0); 1688 ASSERT(to > from); 1689 return ReplacementPart(-from, to); 1690 } 1691 1692 // If tag <= 0 then it is the negation of a start index of a substring of 1693 // the replacement pattern, otherwise it's a value from PartType. 1694 ReplacementPart(int tag, int data) 1695 : tag(tag), data(data) { 1696 // Must be non-positive or a PartType value. 1697 ASSERT(tag < NUMBER_OF_PART_TYPES); 1698 } 1699 // Either a value of PartType or a non-positive number that is 1700 // the negation of an index into the replacement string. 1701 int tag; 1702 // The data value's interpretation depends on the value of tag: 1703 // tag == SUBJECT_PREFIX || 1704 // tag == SUBJECT_SUFFIX: data is unused. 1705 // tag == SUBJECT_CAPTURE: data is the number of the capture. 1706 // tag == REPLACEMENT_SUBSTRING || 1707 // tag == REPLACEMENT_STRING: data is index into array of substrings 1708 // of the replacement string. 1709 // tag <= 0: Temporary representation of the substring of the replacement 1710 // string ranging over -tag .. data. 1711 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the 1712 // substring objects. 1713 int data; 1714 }; 1715 1716 template<typename Char> 1717 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts, 1718 Vector<Char> characters, 1719 int capture_count, 1720 int subject_length) { 1721 int length = characters.length(); 1722 int last = 0; 1723 for (int i = 0; i < length; i++) { 1724 Char c = characters[i]; 1725 if (c == '$') { 1726 int next_index = i + 1; 1727 if (next_index == length) { // No next character! 1728 break; 1729 } 1730 Char c2 = characters[next_index]; 1731 switch (c2) { 1732 case '$': 1733 if (i > last) { 1734 // There is a substring before. Include the first "$". 1735 parts->Add(ReplacementPart::ReplacementSubString(last, next_index)); 1736 last = next_index + 1; // Continue after the second "$". 1737 } else { 1738 // Let the next substring start with the second "$". 1739 last = next_index; 1740 } 1741 i = next_index; 1742 break; 1743 case '`': 1744 if (i > last) { 1745 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 1746 } 1747 parts->Add(ReplacementPart::SubjectPrefix()); 1748 i = next_index; 1749 last = i + 1; 1750 break; 1751 case '\'': 1752 if (i > last) { 1753 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 1754 } 1755 parts->Add(ReplacementPart::SubjectSuffix(subject_length)); 1756 i = next_index; 1757 last = i + 1; 1758 break; 1759 case '&': 1760 if (i > last) { 1761 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 1762 } 1763 parts->Add(ReplacementPart::SubjectMatch()); 1764 i = next_index; 1765 last = i + 1; 1766 break; 1767 case '0': 1768 case '1': 1769 case '2': 1770 case '3': 1771 case '4': 1772 case '5': 1773 case '6': 1774 case '7': 1775 case '8': 1776 case '9': { 1777 int capture_ref = c2 - '0'; 1778 if (capture_ref > capture_count) { 1779 i = next_index; 1780 continue; 1781 } 1782 int second_digit_index = next_index + 1; 1783 if (second_digit_index < length) { 1784 // Peek ahead to see if we have two digits. 1785 Char c3 = characters[second_digit_index]; 1786 if ('0' <= c3 && c3 <= '9') { // Double digits. 1787 int double_digit_ref = capture_ref * 10 + c3 - '0'; 1788 if (double_digit_ref <= capture_count) { 1789 next_index = second_digit_index; 1790 capture_ref = double_digit_ref; 1791 } 1792 } 1793 } 1794 if (capture_ref > 0) { 1795 if (i > last) { 1796 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 1797 } 1798 ASSERT(capture_ref <= capture_count); 1799 parts->Add(ReplacementPart::SubjectCapture(capture_ref)); 1800 last = next_index + 1; 1801 } 1802 i = next_index; 1803 break; 1804 } 1805 default: 1806 i = next_index; 1807 break; 1808 } 1809 } 1810 } 1811 if (length > last) { 1812 if (last == 0) { 1813 parts->Add(ReplacementPart::ReplacementString()); 1814 } else { 1815 parts->Add(ReplacementPart::ReplacementSubString(last, length)); 1816 } 1817 } 1818 } 1819 1820 ZoneList<ReplacementPart> parts_; 1821 ZoneList<Handle<String> > replacement_substrings_; 1822}; 1823 1824 1825void CompiledReplacement::Compile(Handle<String> replacement, 1826 int capture_count, 1827 int subject_length) { 1828 ASSERT(replacement->IsFlat()); 1829 if (replacement->IsAsciiRepresentation()) { 1830 AssertNoAllocation no_alloc; 1831 ParseReplacementPattern(&parts_, 1832 replacement->ToAsciiVector(), 1833 capture_count, 1834 subject_length); 1835 } else { 1836 ASSERT(replacement->IsTwoByteRepresentation()); 1837 AssertNoAllocation no_alloc; 1838 1839 ParseReplacementPattern(&parts_, 1840 replacement->ToUC16Vector(), 1841 capture_count, 1842 subject_length); 1843 } 1844 // Find substrings of replacement string and create them as String objects. 1845 int substring_index = 0; 1846 for (int i = 0, n = parts_.length(); i < n; i++) { 1847 int tag = parts_[i].tag; 1848 if (tag <= 0) { // A replacement string slice. 1849 int from = -tag; 1850 int to = parts_[i].data; 1851 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to)); 1852 parts_[i].tag = REPLACEMENT_SUBSTRING; 1853 parts_[i].data = substring_index; 1854 substring_index++; 1855 } else if (tag == REPLACEMENT_STRING) { 1856 replacement_substrings_.Add(replacement); 1857 parts_[i].data = substring_index; 1858 substring_index++; 1859 } 1860 } 1861} 1862 1863 1864void CompiledReplacement::Apply(ReplacementStringBuilder* builder, 1865 int match_from, 1866 int match_to, 1867 Handle<JSArray> last_match_info) { 1868 for (int i = 0, n = parts_.length(); i < n; i++) { 1869 ReplacementPart part = parts_[i]; 1870 switch (part.tag) { 1871 case SUBJECT_PREFIX: 1872 if (match_from > 0) builder->AddSubjectSlice(0, match_from); 1873 break; 1874 case SUBJECT_SUFFIX: { 1875 int subject_length = part.data; 1876 if (match_to < subject_length) { 1877 builder->AddSubjectSlice(match_to, subject_length); 1878 } 1879 break; 1880 } 1881 case SUBJECT_CAPTURE: { 1882 int capture = part.data; 1883 FixedArray* match_info = FixedArray::cast(last_match_info->elements()); 1884 int from = RegExpImpl::GetCapture(match_info, capture * 2); 1885 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1); 1886 if (from >= 0 && to > from) { 1887 builder->AddSubjectSlice(from, to); 1888 } 1889 break; 1890 } 1891 case REPLACEMENT_SUBSTRING: 1892 case REPLACEMENT_STRING: 1893 builder->AddString(replacement_substrings_[part.data]); 1894 break; 1895 default: 1896 UNREACHABLE(); 1897 } 1898 } 1899} 1900 1901 1902 1903static Object* StringReplaceRegExpWithString(String* subject, 1904 JSRegExp* regexp, 1905 String* replacement, 1906 JSArray* last_match_info) { 1907 ASSERT(subject->IsFlat()); 1908 ASSERT(replacement->IsFlat()); 1909 1910 HandleScope handles; 1911 1912 int length = subject->length(); 1913 Handle<String> subject_handle(subject); 1914 Handle<JSRegExp> regexp_handle(regexp); 1915 Handle<String> replacement_handle(replacement); 1916 Handle<JSArray> last_match_info_handle(last_match_info); 1917 Handle<Object> match = RegExpImpl::Exec(regexp_handle, 1918 subject_handle, 1919 0, 1920 last_match_info_handle); 1921 if (match.is_null()) { 1922 return Failure::Exception(); 1923 } 1924 if (match->IsNull()) { 1925 return *subject_handle; 1926 } 1927 1928 int capture_count = regexp_handle->CaptureCount(); 1929 1930 // CompiledReplacement uses zone allocation. 1931 CompilationZoneScope zone(DELETE_ON_EXIT); 1932 CompiledReplacement compiled_replacement; 1933 compiled_replacement.Compile(replacement_handle, 1934 capture_count, 1935 length); 1936 1937 bool is_global = regexp_handle->GetFlags().is_global(); 1938 1939 // Guessing the number of parts that the final result string is built 1940 // from. Global regexps can match any number of times, so we guess 1941 // conservatively. 1942 int expected_parts = 1943 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1; 1944 ReplacementStringBuilder builder(subject_handle, expected_parts); 1945 1946 // Index of end of last match. 1947 int prev = 0; 1948 1949 // Number of parts added by compiled replacement plus preceeding 1950 // string and possibly suffix after last match. It is possible for 1951 // all components to use two elements when encoded as two smis. 1952 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); 1953 bool matched = true; 1954 do { 1955 ASSERT(last_match_info_handle->HasFastElements()); 1956 // Increase the capacity of the builder before entering local handle-scope, 1957 // so its internal buffer can safely allocate a new handle if it grows. 1958 builder.EnsureCapacity(parts_added_per_loop); 1959 1960 HandleScope loop_scope; 1961 int start, end; 1962 { 1963 AssertNoAllocation match_info_array_is_not_in_a_handle; 1964 FixedArray* match_info_array = 1965 FixedArray::cast(last_match_info_handle->elements()); 1966 1967 ASSERT_EQ(capture_count * 2 + 2, 1968 RegExpImpl::GetLastCaptureCount(match_info_array)); 1969 start = RegExpImpl::GetCapture(match_info_array, 0); 1970 end = RegExpImpl::GetCapture(match_info_array, 1); 1971 } 1972 1973 if (prev < start) { 1974 builder.AddSubjectSlice(prev, start); 1975 } 1976 compiled_replacement.Apply(&builder, 1977 start, 1978 end, 1979 last_match_info_handle); 1980 prev = end; 1981 1982 // Only continue checking for global regexps. 1983 if (!is_global) break; 1984 1985 // Continue from where the match ended, unless it was an empty match. 1986 int next = end; 1987 if (start == end) { 1988 next = end + 1; 1989 if (next > length) break; 1990 } 1991 1992 match = RegExpImpl::Exec(regexp_handle, 1993 subject_handle, 1994 next, 1995 last_match_info_handle); 1996 if (match.is_null()) { 1997 return Failure::Exception(); 1998 } 1999 matched = !match->IsNull(); 2000 } while (matched); 2001 2002 if (prev < length) { 2003 builder.AddSubjectSlice(prev, length); 2004 } 2005 2006 return *(builder.ToString()); 2007} 2008 2009 2010static Object* Runtime_StringReplaceRegExpWithString(Arguments args) { 2011 ASSERT(args.length() == 4); 2012 2013 CONVERT_CHECKED(String, subject, args[0]); 2014 if (!subject->IsFlat()) { 2015 Object* flat_subject = subject->TryFlatten(); 2016 if (flat_subject->IsFailure()) { 2017 return flat_subject; 2018 } 2019 subject = String::cast(flat_subject); 2020 } 2021 2022 CONVERT_CHECKED(String, replacement, args[2]); 2023 if (!replacement->IsFlat()) { 2024 Object* flat_replacement = replacement->TryFlatten(); 2025 if (flat_replacement->IsFailure()) { 2026 return flat_replacement; 2027 } 2028 replacement = String::cast(flat_replacement); 2029 } 2030 2031 CONVERT_CHECKED(JSRegExp, regexp, args[1]); 2032 CONVERT_CHECKED(JSArray, last_match_info, args[3]); 2033 2034 ASSERT(last_match_info->HasFastElements()); 2035 2036 return StringReplaceRegExpWithString(subject, 2037 regexp, 2038 replacement, 2039 last_match_info); 2040} 2041 2042 2043 2044// Cap on the maximal shift in the Boyer-Moore implementation. By setting a 2045// limit, we can fix the size of tables. 2046static const int kBMMaxShift = 0xff; 2047// Reduce alphabet to this size. 2048static const int kBMAlphabetSize = 0x100; 2049// For patterns below this length, the skip length of Boyer-Moore is too short 2050// to compensate for the algorithmic overhead compared to simple brute force. 2051static const int kBMMinPatternLength = 5; 2052 2053// Holds the two buffers used by Boyer-Moore string search's Good Suffix 2054// shift. Only allows the last kBMMaxShift characters of the needle 2055// to be indexed. 2056class BMGoodSuffixBuffers { 2057 public: 2058 BMGoodSuffixBuffers() {} 2059 inline void init(int needle_length) { 2060 ASSERT(needle_length > 1); 2061 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift; 2062 int len = needle_length - start; 2063 biased_suffixes_ = suffixes_ - start; 2064 biased_good_suffix_shift_ = good_suffix_shift_ - start; 2065 for (int i = 0; i <= len; i++) { 2066 good_suffix_shift_[i] = len; 2067 } 2068 } 2069 inline int& suffix(int index) { 2070 ASSERT(biased_suffixes_ + index >= suffixes_); 2071 return biased_suffixes_[index]; 2072 } 2073 inline int& shift(int index) { 2074 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_); 2075 return biased_good_suffix_shift_[index]; 2076 } 2077 private: 2078 int suffixes_[kBMMaxShift + 1]; 2079 int good_suffix_shift_[kBMMaxShift + 1]; 2080 int* biased_suffixes_; 2081 int* biased_good_suffix_shift_; 2082 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers); 2083}; 2084 2085// buffers reused by BoyerMoore 2086static int bad_char_occurrence[kBMAlphabetSize]; 2087static BMGoodSuffixBuffers bmgs_buffers; 2088 2089// Compute the bad-char table for Boyer-Moore in the static buffer. 2090template <typename pchar> 2091static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern, 2092 int start) { 2093 // Run forwards to populate bad_char_table, so that *last* instance 2094 // of character equivalence class is the one registered. 2095 // Notice: Doesn't include the last character. 2096 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1 2097 : kBMAlphabetSize; 2098 if (start == 0) { // All patterns less than kBMMaxShift in length. 2099 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence)); 2100 } else { 2101 for (int i = 0; i < table_size; i++) { 2102 bad_char_occurrence[i] = start - 1; 2103 } 2104 } 2105 for (int i = start; i < pattern.length() - 1; i++) { 2106 pchar c = pattern[i]; 2107 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize; 2108 bad_char_occurrence[bucket] = i; 2109 } 2110} 2111 2112template <typename pchar> 2113static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern, 2114 int start) { 2115 int m = pattern.length(); 2116 int len = m - start; 2117 // Compute Good Suffix tables. 2118 bmgs_buffers.init(m); 2119 2120 bmgs_buffers.shift(m-1) = 1; 2121 bmgs_buffers.suffix(m) = m + 1; 2122 pchar last_char = pattern[m - 1]; 2123 int suffix = m + 1; 2124 for (int i = m; i > start;) { 2125 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) { 2126 if (bmgs_buffers.shift(suffix) == len) { 2127 bmgs_buffers.shift(suffix) = suffix - i; 2128 } 2129 suffix = bmgs_buffers.suffix(suffix); 2130 } 2131 i--; 2132 suffix--; 2133 bmgs_buffers.suffix(i) = suffix; 2134 if (suffix == m) { 2135 // No suffix to extend, so we check against last_char only. 2136 while (i > start && pattern[i - 1] != last_char) { 2137 if (bmgs_buffers.shift(m) == len) { 2138 bmgs_buffers.shift(m) = m - i; 2139 } 2140 i--; 2141 bmgs_buffers.suffix(i) = m; 2142 } 2143 if (i > start) { 2144 i--; 2145 suffix--; 2146 bmgs_buffers.suffix(i) = suffix; 2147 } 2148 } 2149 } 2150 if (suffix < m) { 2151 for (int i = start; i <= m; i++) { 2152 if (bmgs_buffers.shift(i) == len) { 2153 bmgs_buffers.shift(i) = suffix - start; 2154 } 2155 if (i == suffix) { 2156 suffix = bmgs_buffers.suffix(suffix); 2157 } 2158 } 2159 } 2160} 2161 2162template <typename schar, typename pchar> 2163static inline int CharOccurrence(int char_code) { 2164 if (sizeof(schar) == 1) { 2165 return bad_char_occurrence[char_code]; 2166 } 2167 if (sizeof(pchar) == 1) { 2168 if (char_code > String::kMaxAsciiCharCode) { 2169 return -1; 2170 } 2171 return bad_char_occurrence[char_code]; 2172 } 2173 return bad_char_occurrence[char_code % kBMAlphabetSize]; 2174} 2175 2176// Restricted simplified Boyer-Moore string matching. 2177// Uses only the bad-shift table of Boyer-Moore and only uses it 2178// for the character compared to the last character of the needle. 2179template <typename schar, typename pchar> 2180static int BoyerMooreHorspool(Vector<const schar> subject, 2181 Vector<const pchar> pattern, 2182 int start_index, 2183 bool* complete) { 2184 int n = subject.length(); 2185 int m = pattern.length(); 2186 // Only preprocess at most kBMMaxShift last characters of pattern. 2187 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; 2188 2189 BoyerMoorePopulateBadCharTable(pattern, start); 2190 2191 int badness = -m; // How bad we are doing without a good-suffix table. 2192 int idx; // No matches found prior to this index. 2193 pchar last_char = pattern[m - 1]; 2194 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char); 2195 // Perform search 2196 for (idx = start_index; idx <= n - m;) { 2197 int j = m - 1; 2198 int c; 2199 while (last_char != (c = subject[idx + j])) { 2200 int bc_occ = CharOccurrence<schar, pchar>(c); 2201 int shift = j - bc_occ; 2202 idx += shift; 2203 badness += 1 - shift; // at most zero, so badness cannot increase. 2204 if (idx > n - m) { 2205 *complete = true; 2206 return -1; 2207 } 2208 } 2209 j--; 2210 while (j >= 0 && pattern[j] == (subject[idx + j])) j--; 2211 if (j < 0) { 2212 *complete = true; 2213 return idx; 2214 } else { 2215 idx += last_char_shift; 2216 // Badness increases by the number of characters we have 2217 // checked, and decreases by the number of characters we 2218 // can skip by shifting. It's a measure of how we are doing 2219 // compared to reading each character exactly once. 2220 badness += (m - j) - last_char_shift; 2221 if (badness > 0) { 2222 *complete = false; 2223 return idx; 2224 } 2225 } 2226 } 2227 *complete = true; 2228 return -1; 2229} 2230 2231 2232template <typename schar, typename pchar> 2233static int BoyerMooreIndexOf(Vector<const schar> subject, 2234 Vector<const pchar> pattern, 2235 int idx) { 2236 int n = subject.length(); 2237 int m = pattern.length(); 2238 // Only preprocess at most kBMMaxShift last characters of pattern. 2239 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; 2240 2241 // Build the Good Suffix table and continue searching. 2242 BoyerMoorePopulateGoodSuffixTable(pattern, start); 2243 pchar last_char = pattern[m - 1]; 2244 // Continue search from i. 2245 while (idx <= n - m) { 2246 int j = m - 1; 2247 schar c; 2248 while (last_char != (c = subject[idx + j])) { 2249 int shift = j - CharOccurrence<schar, pchar>(c); 2250 idx += shift; 2251 if (idx > n - m) { 2252 return -1; 2253 } 2254 } 2255 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--; 2256 if (j < 0) { 2257 return idx; 2258 } else if (j < start) { 2259 // we have matched more than our tables allow us to be smart about. 2260 // Fall back on BMH shift. 2261 idx += m - 1 - CharOccurrence<schar, pchar>(last_char); 2262 } else { 2263 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift. 2264 int bc_occ = CharOccurrence<schar, pchar>(c); 2265 int shift = j - bc_occ; // Bad-char shift. 2266 if (gs_shift > shift) { 2267 shift = gs_shift; 2268 } 2269 idx += shift; 2270 } 2271 } 2272 2273 return -1; 2274} 2275 2276 2277template <typename schar> 2278static int SingleCharIndexOf(Vector<const schar> string, 2279 schar pattern_char, 2280 int start_index) { 2281 for (int i = start_index, n = string.length(); i < n; i++) { 2282 if (pattern_char == string[i]) { 2283 return i; 2284 } 2285 } 2286 return -1; 2287} 2288 2289// Trivial string search for shorter strings. 2290// On return, if "complete" is set to true, the return value is the 2291// final result of searching for the patter in the subject. 2292// If "complete" is set to false, the return value is the index where 2293// further checking should start, i.e., it's guaranteed that the pattern 2294// does not occur at a position prior to the returned index. 2295template <typename pchar, typename schar> 2296static int SimpleIndexOf(Vector<const schar> subject, 2297 Vector<const pchar> pattern, 2298 int idx, 2299 bool* complete) { 2300 // Badness is a count of how much work we have done. When we have 2301 // done enough work we decide it's probably worth switching to a better 2302 // algorithm. 2303 int badness = -10 - (pattern.length() << 2); 2304 // We know our pattern is at least 2 characters, we cache the first so 2305 // the common case of the first character not matching is faster. 2306 pchar pattern_first_char = pattern[0]; 2307 2308 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) { 2309 badness++; 2310 if (badness > 0) { 2311 *complete = false; 2312 return i; 2313 } 2314 if (subject[i] != pattern_first_char) continue; 2315 int j = 1; 2316 do { 2317 if (pattern[j] != subject[i+j]) { 2318 break; 2319 } 2320 j++; 2321 } while (j < pattern.length()); 2322 if (j == pattern.length()) { 2323 *complete = true; 2324 return i; 2325 } 2326 badness += j; 2327 } 2328 *complete = true; 2329 return -1; 2330} 2331 2332// Simple indexOf that never bails out. For short patterns only. 2333template <typename pchar, typename schar> 2334static int SimpleIndexOf(Vector<const schar> subject, 2335 Vector<const pchar> pattern, 2336 int idx) { 2337 pchar pattern_first_char = pattern[0]; 2338 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) { 2339 if (subject[i] != pattern_first_char) continue; 2340 int j = 1; 2341 do { 2342 if (pattern[j] != subject[i+j]) { 2343 break; 2344 } 2345 j++; 2346 } while (j < pattern.length()); 2347 if (j == pattern.length()) { 2348 return i; 2349 } 2350 } 2351 return -1; 2352} 2353 2354 2355// Dispatch to different algorithms. 2356template <typename schar, typename pchar> 2357static int StringMatchStrategy(Vector<const schar> sub, 2358 Vector<const pchar> pat, 2359 int start_index) { 2360 ASSERT(pat.length() > 1); 2361 2362 // We have an ASCII haystack and a non-ASCII needle. Check if there 2363 // really is a non-ASCII character in the needle and bail out if there 2364 // is. 2365 if (sizeof(pchar) > 1 && sizeof(schar) == 1) { 2366 for (int i = 0; i < pat.length(); i++) { 2367 uc16 c = pat[i]; 2368 if (c > String::kMaxAsciiCharCode) { 2369 return -1; 2370 } 2371 } 2372 } 2373 if (pat.length() < kBMMinPatternLength) { 2374 // We don't believe fancy searching can ever be more efficient. 2375 // The max shift of Boyer-Moore on a pattern of this length does 2376 // not compensate for the overhead. 2377 return SimpleIndexOf(sub, pat, start_index); 2378 } 2379 // Try algorithms in order of increasing setup cost and expected performance. 2380 bool complete; 2381 int idx = SimpleIndexOf(sub, pat, start_index, &complete); 2382 if (complete) return idx; 2383 idx = BoyerMooreHorspool(sub, pat, idx, &complete); 2384 if (complete) return idx; 2385 return BoyerMooreIndexOf(sub, pat, idx); 2386} 2387 2388// Perform string match of pattern on subject, starting at start index. 2389// Caller must ensure that 0 <= start_index <= sub->length(), 2390// and should check that pat->length() + start_index <= sub->length() 2391int Runtime::StringMatch(Handle<String> sub, 2392 Handle<String> pat, 2393 int start_index) { 2394 ASSERT(0 <= start_index); 2395 ASSERT(start_index <= sub->length()); 2396 2397 int pattern_length = pat->length(); 2398 if (pattern_length == 0) return start_index; 2399 2400 int subject_length = sub->length(); 2401 if (start_index + pattern_length > subject_length) return -1; 2402 2403 if (!sub->IsFlat()) { 2404 FlattenString(sub); 2405 } 2406 // Searching for one specific character is common. For one 2407 // character patterns linear search is necessary, so any smart 2408 // algorithm is unnecessary overhead. 2409 if (pattern_length == 1) { 2410 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid 2411 if (sub->IsAsciiRepresentation()) { 2412 uc16 pchar = pat->Get(0); 2413 if (pchar > String::kMaxAsciiCharCode) { 2414 return -1; 2415 } 2416 Vector<const char> ascii_vector = 2417 sub->ToAsciiVector().SubVector(start_index, subject_length); 2418 const void* pos = memchr(ascii_vector.start(), 2419 static_cast<const char>(pchar), 2420 static_cast<size_t>(ascii_vector.length())); 2421 if (pos == NULL) { 2422 return -1; 2423 } 2424 return static_cast<int>(reinterpret_cast<const char*>(pos) 2425 - ascii_vector.start() + start_index); 2426 } 2427 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index); 2428 } 2429 2430 if (!pat->IsFlat()) { 2431 FlattenString(pat); 2432 } 2433 2434 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid 2435 // dispatch on type of strings 2436 if (pat->IsAsciiRepresentation()) { 2437 Vector<const char> pat_vector = pat->ToAsciiVector(); 2438 if (sub->IsAsciiRepresentation()) { 2439 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); 2440 } 2441 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); 2442 } 2443 Vector<const uc16> pat_vector = pat->ToUC16Vector(); 2444 if (sub->IsAsciiRepresentation()) { 2445 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); 2446 } 2447 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); 2448} 2449 2450 2451static Object* Runtime_StringIndexOf(Arguments args) { 2452 HandleScope scope; // create a new handle scope 2453 ASSERT(args.length() == 3); 2454 2455 CONVERT_ARG_CHECKED(String, sub, 0); 2456 CONVERT_ARG_CHECKED(String, pat, 1); 2457 2458 Object* index = args[2]; 2459 uint32_t start_index; 2460 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); 2461 2462 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); 2463 int position = Runtime::StringMatch(sub, pat, start_index); 2464 return Smi::FromInt(position); 2465} 2466 2467 2468static Object* Runtime_StringLastIndexOf(Arguments args) { 2469 NoHandleAllocation ha; 2470 ASSERT(args.length() == 3); 2471 2472 CONVERT_CHECKED(String, sub, args[0]); 2473 CONVERT_CHECKED(String, pat, args[1]); 2474 Object* index = args[2]; 2475 2476 sub->TryFlattenIfNotFlat(); 2477 pat->TryFlattenIfNotFlat(); 2478 2479 uint32_t start_index; 2480 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); 2481 2482 uint32_t pattern_length = pat->length(); 2483 uint32_t sub_length = sub->length(); 2484 2485 if (start_index + pattern_length > sub_length) { 2486 start_index = sub_length - pattern_length; 2487 } 2488 2489 for (int i = start_index; i >= 0; i--) { 2490 bool found = true; 2491 for (uint32_t j = 0; j < pattern_length; j++) { 2492 if (sub->Get(i + j) != pat->Get(j)) { 2493 found = false; 2494 break; 2495 } 2496 } 2497 if (found) return Smi::FromInt(i); 2498 } 2499 2500 return Smi::FromInt(-1); 2501} 2502 2503 2504static Object* Runtime_StringLocaleCompare(Arguments args) { 2505 NoHandleAllocation ha; 2506 ASSERT(args.length() == 2); 2507 2508 CONVERT_CHECKED(String, str1, args[0]); 2509 CONVERT_CHECKED(String, str2, args[1]); 2510 2511 if (str1 == str2) return Smi::FromInt(0); // Equal. 2512 int str1_length = str1->length(); 2513 int str2_length = str2->length(); 2514 2515 // Decide trivial cases without flattening. 2516 if (str1_length == 0) { 2517 if (str2_length == 0) return Smi::FromInt(0); // Equal. 2518 return Smi::FromInt(-str2_length); 2519 } else { 2520 if (str2_length == 0) return Smi::FromInt(str1_length); 2521 } 2522 2523 int end = str1_length < str2_length ? str1_length : str2_length; 2524 2525 // No need to flatten if we are going to find the answer on the first 2526 // character. At this point we know there is at least one character 2527 // in each string, due to the trivial case handling above. 2528 int d = str1->Get(0) - str2->Get(0); 2529 if (d != 0) return Smi::FromInt(d); 2530 2531 str1->TryFlattenIfNotFlat(); 2532 str2->TryFlattenIfNotFlat(); 2533 2534 static StringInputBuffer buf1; 2535 static StringInputBuffer buf2; 2536 2537 buf1.Reset(str1); 2538 buf2.Reset(str2); 2539 2540 for (int i = 0; i < end; i++) { 2541 uint16_t char1 = buf1.GetNext(); 2542 uint16_t char2 = buf2.GetNext(); 2543 if (char1 != char2) return Smi::FromInt(char1 - char2); 2544 } 2545 2546 return Smi::FromInt(str1_length - str2_length); 2547} 2548 2549 2550static Object* Runtime_SubString(Arguments args) { 2551 NoHandleAllocation ha; 2552 ASSERT(args.length() == 3); 2553 2554 CONVERT_CHECKED(String, value, args[0]); 2555 Object* from = args[1]; 2556 Object* to = args[2]; 2557 int start, end; 2558 // We have a fast integer-only case here to avoid a conversion to double in 2559 // the common case where from and to are Smis. 2560 if (from->IsSmi() && to->IsSmi()) { 2561 start = Smi::cast(from)->value(); 2562 end = Smi::cast(to)->value(); 2563 } else { 2564 CONVERT_DOUBLE_CHECKED(from_number, from); 2565 CONVERT_DOUBLE_CHECKED(to_number, to); 2566 start = FastD2I(from_number); 2567 end = FastD2I(to_number); 2568 } 2569 RUNTIME_ASSERT(end >= start); 2570 RUNTIME_ASSERT(start >= 0); 2571 RUNTIME_ASSERT(end <= value->length()); 2572 Counters::sub_string_runtime.Increment(); 2573 return value->SubString(start, end); 2574} 2575 2576 2577static Object* Runtime_StringMatch(Arguments args) { 2578 ASSERT_EQ(3, args.length()); 2579 2580 CONVERT_ARG_CHECKED(String, subject, 0); 2581 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1); 2582 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2); 2583 HandleScope handles; 2584 2585 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info); 2586 2587 if (match.is_null()) { 2588 return Failure::Exception(); 2589 } 2590 if (match->IsNull()) { 2591 return Heap::null_value(); 2592 } 2593 int length = subject->length(); 2594 2595 CompilationZoneScope zone_space(DELETE_ON_EXIT); 2596 ZoneList<int> offsets(8); 2597 do { 2598 int start; 2599 int end; 2600 { 2601 AssertNoAllocation no_alloc; 2602 FixedArray* elements = FixedArray::cast(regexp_info->elements()); 2603 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value(); 2604 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value(); 2605 } 2606 offsets.Add(start); 2607 offsets.Add(end); 2608 int index = start < end ? end : end + 1; 2609 if (index > length) break; 2610 match = RegExpImpl::Exec(regexp, subject, index, regexp_info); 2611 if (match.is_null()) { 2612 return Failure::Exception(); 2613 } 2614 } while (!match->IsNull()); 2615 int matches = offsets.length() / 2; 2616 Handle<FixedArray> elements = Factory::NewFixedArray(matches); 2617 for (int i = 0; i < matches ; i++) { 2618 int from = offsets.at(i * 2); 2619 int to = offsets.at(i * 2 + 1); 2620 elements->set(i, *Factory::NewSubString(subject, from, to)); 2621 } 2622 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements); 2623 result->set_length(Smi::FromInt(matches)); 2624 return *result; 2625} 2626 2627 2628static Object* Runtime_NumberToRadixString(Arguments args) { 2629 NoHandleAllocation ha; 2630 ASSERT(args.length() == 2); 2631 2632 // Fast case where the result is a one character string. 2633 if (args[0]->IsSmi() && args[1]->IsSmi()) { 2634 int value = Smi::cast(args[0])->value(); 2635 int radix = Smi::cast(args[1])->value(); 2636 if (value >= 0 && value < radix) { 2637 RUNTIME_ASSERT(radix <= 36); 2638 // Character array used for conversion. 2639 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 2640 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]); 2641 } 2642 } 2643 2644 // Slow case. 2645 CONVERT_DOUBLE_CHECKED(value, args[0]); 2646 if (isnan(value)) { 2647 return Heap::AllocateStringFromAscii(CStrVector("NaN")); 2648 } 2649 if (isinf(value)) { 2650 if (value < 0) { 2651 return Heap::AllocateStringFromAscii(CStrVector("-Infinity")); 2652 } 2653 return Heap::AllocateStringFromAscii(CStrVector("Infinity")); 2654 } 2655 CONVERT_DOUBLE_CHECKED(radix_number, args[1]); 2656 int radix = FastD2I(radix_number); 2657 RUNTIME_ASSERT(2 <= radix && radix <= 36); 2658 char* str = DoubleToRadixCString(value, radix); 2659 Object* result = Heap::AllocateStringFromAscii(CStrVector(str)); 2660 DeleteArray(str); 2661 return result; 2662} 2663 2664 2665static Object* Runtime_NumberToFixed(Arguments args) { 2666 NoHandleAllocation ha; 2667 ASSERT(args.length() == 2); 2668 2669 CONVERT_DOUBLE_CHECKED(value, args[0]); 2670 if (isnan(value)) { 2671 return Heap::AllocateStringFromAscii(CStrVector("NaN")); 2672 } 2673 if (isinf(value)) { 2674 if (value < 0) { 2675 return Heap::AllocateStringFromAscii(CStrVector("-Infinity")); 2676 } 2677 return Heap::AllocateStringFromAscii(CStrVector("Infinity")); 2678 } 2679 CONVERT_DOUBLE_CHECKED(f_number, args[1]); 2680 int f = FastD2I(f_number); 2681 RUNTIME_ASSERT(f >= 0); 2682 char* str = DoubleToFixedCString(value, f); 2683 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); 2684 DeleteArray(str); 2685 return res; 2686} 2687 2688 2689static Object* Runtime_NumberToExponential(Arguments args) { 2690 NoHandleAllocation ha; 2691 ASSERT(args.length() == 2); 2692 2693 CONVERT_DOUBLE_CHECKED(value, args[0]); 2694 if (isnan(value)) { 2695 return Heap::AllocateStringFromAscii(CStrVector("NaN")); 2696 } 2697 if (isinf(value)) { 2698 if (value < 0) { 2699 return Heap::AllocateStringFromAscii(CStrVector("-Infinity")); 2700 } 2701 return Heap::AllocateStringFromAscii(CStrVector("Infinity")); 2702 } 2703 CONVERT_DOUBLE_CHECKED(f_number, args[1]); 2704 int f = FastD2I(f_number); 2705 RUNTIME_ASSERT(f >= -1 && f <= 20); 2706 char* str = DoubleToExponentialCString(value, f); 2707 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); 2708 DeleteArray(str); 2709 return res; 2710} 2711 2712 2713static Object* Runtime_NumberToPrecision(Arguments args) { 2714 NoHandleAllocation ha; 2715 ASSERT(args.length() == 2); 2716 2717 CONVERT_DOUBLE_CHECKED(value, args[0]); 2718 if (isnan(value)) { 2719 return Heap::AllocateStringFromAscii(CStrVector("NaN")); 2720 } 2721 if (isinf(value)) { 2722 if (value < 0) { 2723 return Heap::AllocateStringFromAscii(CStrVector("-Infinity")); 2724 } 2725 return Heap::AllocateStringFromAscii(CStrVector("Infinity")); 2726 } 2727 CONVERT_DOUBLE_CHECKED(f_number, args[1]); 2728 int f = FastD2I(f_number); 2729 RUNTIME_ASSERT(f >= 1 && f <= 21); 2730 char* str = DoubleToPrecisionCString(value, f); 2731 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); 2732 DeleteArray(str); 2733 return res; 2734} 2735 2736 2737// Returns a single character string where first character equals 2738// string->Get(index). 2739static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { 2740 if (index < static_cast<uint32_t>(string->length())) { 2741 string->TryFlattenIfNotFlat(); 2742 return LookupSingleCharacterStringFromCode( 2743 string->Get(index)); 2744 } 2745 return Execution::CharAt(string, index); 2746} 2747 2748 2749Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { 2750 // Handle [] indexing on Strings 2751 if (object->IsString()) { 2752 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); 2753 if (!result->IsUndefined()) return *result; 2754 } 2755 2756 // Handle [] indexing on String objects 2757 if (object->IsStringObjectWithCharacterAt(index)) { 2758 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 2759 Handle<Object> result = 2760 GetCharAt(Handle<String>(String::cast(js_value->value())), index); 2761 if (!result->IsUndefined()) return *result; 2762 } 2763 2764 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 2765 Handle<Object> prototype = GetPrototype(object); 2766 return prototype->GetElement(index); 2767 } 2768 2769 return object->GetElement(index); 2770} 2771 2772 2773Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) { 2774 HandleScope scope; 2775 2776 if (object->IsUndefined() || object->IsNull()) { 2777 Handle<Object> args[2] = { key, object }; 2778 Handle<Object> error = 2779 Factory::NewTypeError("non_object_property_load", 2780 HandleVector(args, 2)); 2781 return Top::Throw(*error); 2782 } 2783 2784 // Check if the given key is an array index. 2785 uint32_t index; 2786 if (Array::IndexFromObject(*key, &index)) { 2787 return GetElementOrCharAt(object, index); 2788 } 2789 2790 // Convert the key to a string - possibly by calling back into JavaScript. 2791 Handle<String> name; 2792 if (key->IsString()) { 2793 name = Handle<String>::cast(key); 2794 } else { 2795 bool has_pending_exception = false; 2796 Handle<Object> converted = 2797 Execution::ToString(key, &has_pending_exception); 2798 if (has_pending_exception) return Failure::Exception(); 2799 name = Handle<String>::cast(converted); 2800 } 2801 2802 // Check if the name is trivially convertible to an index and get 2803 // the element if so. 2804 if (name->AsArrayIndex(&index)) { 2805 return GetElementOrCharAt(object, index); 2806 } else { 2807 PropertyAttributes attr; 2808 return object->GetProperty(*name, &attr); 2809 } 2810} 2811 2812 2813static Object* Runtime_GetProperty(Arguments args) { 2814 NoHandleAllocation ha; 2815 ASSERT(args.length() == 2); 2816 2817 Handle<Object> object = args.at<Object>(0); 2818 Handle<Object> key = args.at<Object>(1); 2819 2820 return Runtime::GetObjectProperty(object, key); 2821} 2822 2823 2824// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric. 2825static Object* Runtime_KeyedGetProperty(Arguments args) { 2826 NoHandleAllocation ha; 2827 ASSERT(args.length() == 2); 2828 2829 // Fast cases for getting named properties of the receiver JSObject 2830 // itself. 2831 // 2832 // The global proxy objects has to be excluded since LocalLookup on 2833 // the global proxy object can return a valid result even though the 2834 // global proxy object never has properties. This is the case 2835 // because the global proxy object forwards everything to its hidden 2836 // prototype including local lookups. 2837 // 2838 // Additionally, we need to make sure that we do not cache results 2839 // for objects that require access checks. 2840 if (args[0]->IsJSObject() && 2841 !args[0]->IsJSGlobalProxy() && 2842 !args[0]->IsAccessCheckNeeded() && 2843 args[1]->IsString()) { 2844 JSObject* receiver = JSObject::cast(args[0]); 2845 String* key = String::cast(args[1]); 2846 if (receiver->HasFastProperties()) { 2847 // Attempt to use lookup cache. 2848 Map* receiver_map = receiver->map(); 2849 int offset = KeyedLookupCache::Lookup(receiver_map, key); 2850 if (offset != -1) { 2851 Object* value = receiver->FastPropertyAt(offset); 2852 return value->IsTheHole() ? Heap::undefined_value() : value; 2853 } 2854 // Lookup cache miss. Perform lookup and update the cache if appropriate. 2855 LookupResult result; 2856 receiver->LocalLookup(key, &result); 2857 if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) { 2858 int offset = result.GetFieldIndex(); 2859 KeyedLookupCache::Update(receiver_map, key, offset); 2860 return receiver->FastPropertyAt(offset); 2861 } 2862 } else { 2863 // Attempt dictionary lookup. 2864 StringDictionary* dictionary = receiver->property_dictionary(); 2865 int entry = dictionary->FindEntry(key); 2866 if ((entry != StringDictionary::kNotFound) && 2867 (dictionary->DetailsAt(entry).type() == NORMAL)) { 2868 Object* value = dictionary->ValueAt(entry); 2869 if (!receiver->IsGlobalObject()) return value; 2870 value = JSGlobalPropertyCell::cast(value)->value(); 2871 if (!value->IsTheHole()) return value; 2872 // If value is the hole do the general lookup. 2873 } 2874 } 2875 } else if (args[0]->IsString() && args[1]->IsSmi()) { 2876 // Fast case for string indexing using [] with a smi index. 2877 HandleScope scope; 2878 Handle<String> str = args.at<String>(0); 2879 int index = Smi::cast(args[1])->value(); 2880 Handle<Object> result = GetCharAt(str, index); 2881 return *result; 2882 } 2883 2884 // Fall back to GetObjectProperty. 2885 return Runtime::GetObjectProperty(args.at<Object>(0), 2886 args.at<Object>(1)); 2887} 2888 2889 2890Object* Runtime::SetObjectProperty(Handle<Object> object, 2891 Handle<Object> key, 2892 Handle<Object> value, 2893 PropertyAttributes attr) { 2894 HandleScope scope; 2895 2896 if (object->IsUndefined() || object->IsNull()) { 2897 Handle<Object> args[2] = { key, object }; 2898 Handle<Object> error = 2899 Factory::NewTypeError("non_object_property_store", 2900 HandleVector(args, 2)); 2901 return Top::Throw(*error); 2902 } 2903 2904 // If the object isn't a JavaScript object, we ignore the store. 2905 if (!object->IsJSObject()) return *value; 2906 2907 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 2908 2909 // Check if the given key is an array index. 2910 uint32_t index; 2911 if (Array::IndexFromObject(*key, &index)) { 2912 ASSERT(attr == NONE); 2913 2914 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 2915 // of a string using [] notation. We need to support this too in 2916 // JavaScript. 2917 // In the case of a String object we just need to redirect the assignment to 2918 // the underlying string if the index is in range. Since the underlying 2919 // string does nothing with the assignment then we can ignore such 2920 // assignments. 2921 if (js_object->IsStringObjectWithCharacterAt(index)) { 2922 return *value; 2923 } 2924 2925 Handle<Object> result = SetElement(js_object, index, value); 2926 if (result.is_null()) return Failure::Exception(); 2927 return *value; 2928 } 2929 2930 if (key->IsString()) { 2931 Handle<Object> result; 2932 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { 2933 ASSERT(attr == NONE); 2934 result = SetElement(js_object, index, value); 2935 } else { 2936 Handle<String> key_string = Handle<String>::cast(key); 2937 key_string->TryFlattenIfNotFlat(); 2938 result = SetProperty(js_object, key_string, value, attr); 2939 } 2940 if (result.is_null()) return Failure::Exception(); 2941 return *value; 2942 } 2943 2944 // Call-back into JavaScript to convert the key to a string. 2945 bool has_pending_exception = false; 2946 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 2947 if (has_pending_exception) return Failure::Exception(); 2948 Handle<String> name = Handle<String>::cast(converted); 2949 2950 if (name->AsArrayIndex(&index)) { 2951 ASSERT(attr == NONE); 2952 return js_object->SetElement(index, *value); 2953 } else { 2954 return js_object->SetProperty(*name, *value, attr); 2955 } 2956} 2957 2958 2959Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object, 2960 Handle<Object> key, 2961 Handle<Object> value, 2962 PropertyAttributes attr) { 2963 HandleScope scope; 2964 2965 // Check if the given key is an array index. 2966 uint32_t index; 2967 if (Array::IndexFromObject(*key, &index)) { 2968 ASSERT(attr == NONE); 2969 2970 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 2971 // of a string using [] notation. We need to support this too in 2972 // JavaScript. 2973 // In the case of a String object we just need to redirect the assignment to 2974 // the underlying string if the index is in range. Since the underlying 2975 // string does nothing with the assignment then we can ignore such 2976 // assignments. 2977 if (js_object->IsStringObjectWithCharacterAt(index)) { 2978 return *value; 2979 } 2980 2981 return js_object->SetElement(index, *value); 2982 } 2983 2984 if (key->IsString()) { 2985 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { 2986 ASSERT(attr == NONE); 2987 return js_object->SetElement(index, *value); 2988 } else { 2989 Handle<String> key_string = Handle<String>::cast(key); 2990 key_string->TryFlattenIfNotFlat(); 2991 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string, 2992 *value, 2993 attr); 2994 } 2995 } 2996 2997 // Call-back into JavaScript to convert the key to a string. 2998 bool has_pending_exception = false; 2999 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 3000 if (has_pending_exception) return Failure::Exception(); 3001 Handle<String> name = Handle<String>::cast(converted); 3002 3003 if (name->AsArrayIndex(&index)) { 3004 ASSERT(attr == NONE); 3005 return js_object->SetElement(index, *value); 3006 } else { 3007 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr); 3008 } 3009} 3010 3011 3012Object* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object, 3013 Handle<Object> key) { 3014 HandleScope scope; 3015 3016 // Check if the given key is an array index. 3017 uint32_t index; 3018 if (Array::IndexFromObject(*key, &index)) { 3019 // In Firefox/SpiderMonkey, Safari and Opera you can access the 3020 // characters of a string using [] notation. In the case of a 3021 // String object we just need to redirect the deletion to the 3022 // underlying string if the index is in range. Since the 3023 // underlying string does nothing with the deletion, we can ignore 3024 // such deletions. 3025 if (js_object->IsStringObjectWithCharacterAt(index)) { 3026 return Heap::true_value(); 3027 } 3028 3029 return js_object->DeleteElement(index, JSObject::FORCE_DELETION); 3030 } 3031 3032 Handle<String> key_string; 3033 if (key->IsString()) { 3034 key_string = Handle<String>::cast(key); 3035 } else { 3036 // Call-back into JavaScript to convert the key to a string. 3037 bool has_pending_exception = false; 3038 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 3039 if (has_pending_exception) return Failure::Exception(); 3040 key_string = Handle<String>::cast(converted); 3041 } 3042 3043 key_string->TryFlattenIfNotFlat(); 3044 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); 3045} 3046 3047 3048static Object* Runtime_SetProperty(Arguments args) { 3049 NoHandleAllocation ha; 3050 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); 3051 3052 Handle<Object> object = args.at<Object>(0); 3053 Handle<Object> key = args.at<Object>(1); 3054 Handle<Object> value = args.at<Object>(2); 3055 3056 // Compute attributes. 3057 PropertyAttributes attributes = NONE; 3058 if (args.length() == 4) { 3059 CONVERT_CHECKED(Smi, value_obj, args[3]); 3060 int unchecked_value = value_obj->value(); 3061 // Only attribute bits should be set. 3062 RUNTIME_ASSERT( 3063 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 3064 attributes = static_cast<PropertyAttributes>(unchecked_value); 3065 } 3066 return Runtime::SetObjectProperty(object, key, value, attributes); 3067} 3068 3069 3070// Set a local property, even if it is READ_ONLY. If the property does not 3071// exist, it will be added with attributes NONE. 3072static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) { 3073 NoHandleAllocation ha; 3074 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); 3075 CONVERT_CHECKED(JSObject, object, args[0]); 3076 CONVERT_CHECKED(String, name, args[1]); 3077 // Compute attributes. 3078 PropertyAttributes attributes = NONE; 3079 if (args.length() == 4) { 3080 CONVERT_CHECKED(Smi, value_obj, args[3]); 3081 int unchecked_value = value_obj->value(); 3082 // Only attribute bits should be set. 3083 RUNTIME_ASSERT( 3084 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 3085 attributes = static_cast<PropertyAttributes>(unchecked_value); 3086 } 3087 3088 return object-> 3089 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes); 3090} 3091 3092 3093static Object* Runtime_DeleteProperty(Arguments args) { 3094 NoHandleAllocation ha; 3095 ASSERT(args.length() == 2); 3096 3097 CONVERT_CHECKED(JSObject, object, args[0]); 3098 CONVERT_CHECKED(String, key, args[1]); 3099 return object->DeleteProperty(key, JSObject::NORMAL_DELETION); 3100} 3101 3102 3103static Object* HasLocalPropertyImplementation(Handle<JSObject> object, 3104 Handle<String> key) { 3105 if (object->HasLocalProperty(*key)) return Heap::true_value(); 3106 // Handle hidden prototypes. If there's a hidden prototype above this thing 3107 // then we have to check it for properties, because they are supposed to 3108 // look like they are on this object. 3109 Handle<Object> proto(object->GetPrototype()); 3110 if (proto->IsJSObject() && 3111 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { 3112 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key); 3113 } 3114 return Heap::false_value(); 3115} 3116 3117 3118static Object* Runtime_HasLocalProperty(Arguments args) { 3119 NoHandleAllocation ha; 3120 ASSERT(args.length() == 2); 3121 CONVERT_CHECKED(String, key, args[1]); 3122 3123 Object* obj = args[0]; 3124 // Only JS objects can have properties. 3125 if (obj->IsJSObject()) { 3126 JSObject* object = JSObject::cast(obj); 3127 // Fast case - no interceptors. 3128 if (object->HasRealNamedProperty(key)) return Heap::true_value(); 3129 // Slow case. Either it's not there or we have an interceptor. We should 3130 // have handles for this kind of deal. 3131 HandleScope scope; 3132 return HasLocalPropertyImplementation(Handle<JSObject>(object), 3133 Handle<String>(key)); 3134 } else if (obj->IsString()) { 3135 // Well, there is one exception: Handle [] on strings. 3136 uint32_t index; 3137 if (key->AsArrayIndex(&index)) { 3138 String* string = String::cast(obj); 3139 if (index < static_cast<uint32_t>(string->length())) 3140 return Heap::true_value(); 3141 } 3142 } 3143 return Heap::false_value(); 3144} 3145 3146 3147static Object* Runtime_HasProperty(Arguments args) { 3148 NoHandleAllocation na; 3149 ASSERT(args.length() == 2); 3150 3151 // Only JS objects can have properties. 3152 if (args[0]->IsJSObject()) { 3153 JSObject* object = JSObject::cast(args[0]); 3154 CONVERT_CHECKED(String, key, args[1]); 3155 if (object->HasProperty(key)) return Heap::true_value(); 3156 } 3157 return Heap::false_value(); 3158} 3159 3160 3161static Object* Runtime_HasElement(Arguments args) { 3162 NoHandleAllocation na; 3163 ASSERT(args.length() == 2); 3164 3165 // Only JS objects can have elements. 3166 if (args[0]->IsJSObject()) { 3167 JSObject* object = JSObject::cast(args[0]); 3168 CONVERT_CHECKED(Smi, index_obj, args[1]); 3169 uint32_t index = index_obj->value(); 3170 if (object->HasElement(index)) return Heap::true_value(); 3171 } 3172 return Heap::false_value(); 3173} 3174 3175 3176static Object* Runtime_IsPropertyEnumerable(Arguments args) { 3177 NoHandleAllocation ha; 3178 ASSERT(args.length() == 2); 3179 3180 CONVERT_CHECKED(JSObject, object, args[0]); 3181 CONVERT_CHECKED(String, key, args[1]); 3182 3183 uint32_t index; 3184 if (key->AsArrayIndex(&index)) { 3185 return Heap::ToBoolean(object->HasElement(index)); 3186 } 3187 3188 PropertyAttributes att = object->GetLocalPropertyAttribute(key); 3189 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0); 3190} 3191 3192 3193static Object* Runtime_GetPropertyNames(Arguments args) { 3194 HandleScope scope; 3195 ASSERT(args.length() == 1); 3196 CONVERT_ARG_CHECKED(JSObject, object, 0); 3197 return *GetKeysFor(object); 3198} 3199 3200 3201// Returns either a FixedArray as Runtime_GetPropertyNames, 3202// or, if the given object has an enum cache that contains 3203// all enumerable properties of the object and its prototypes 3204// have none, the map of the object. This is used to speed up 3205// the check for deletions during a for-in. 3206static Object* Runtime_GetPropertyNamesFast(Arguments args) { 3207 ASSERT(args.length() == 1); 3208 3209 CONVERT_CHECKED(JSObject, raw_object, args[0]); 3210 3211 if (raw_object->IsSimpleEnum()) return raw_object->map(); 3212 3213 HandleScope scope; 3214 Handle<JSObject> object(raw_object); 3215 Handle<FixedArray> content = GetKeysInFixedArrayFor(object, 3216 INCLUDE_PROTOS); 3217 3218 // Test again, since cache may have been built by preceding call. 3219 if (object->IsSimpleEnum()) return object->map(); 3220 3221 return *content; 3222} 3223 3224 3225// Find the length of the prototype chain that is to to handled as one. If a 3226// prototype object is hidden it is to be viewed as part of the the object it 3227// is prototype for. 3228static int LocalPrototypeChainLength(JSObject* obj) { 3229 int count = 1; 3230 Object* proto = obj->GetPrototype(); 3231 while (proto->IsJSObject() && 3232 JSObject::cast(proto)->map()->is_hidden_prototype()) { 3233 count++; 3234 proto = JSObject::cast(proto)->GetPrototype(); 3235 } 3236 return count; 3237} 3238 3239 3240// Return the names of the local named properties. 3241// args[0]: object 3242static Object* Runtime_GetLocalPropertyNames(Arguments args) { 3243 HandleScope scope; 3244 ASSERT(args.length() == 1); 3245 if (!args[0]->IsJSObject()) { 3246 return Heap::undefined_value(); 3247 } 3248 CONVERT_ARG_CHECKED(JSObject, obj, 0); 3249 3250 // Skip the global proxy as it has no properties and always delegates to the 3251 // real global object. 3252 if (obj->IsJSGlobalProxy()) { 3253 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 3254 } 3255 3256 // Find the number of objects making up this. 3257 int length = LocalPrototypeChainLength(*obj); 3258 3259 // Find the number of local properties for each of the objects. 3260 int* local_property_count = NewArray<int>(length); 3261 int total_property_count = 0; 3262 Handle<JSObject> jsproto = obj; 3263 for (int i = 0; i < length; i++) { 3264 int n; 3265 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE)); 3266 local_property_count[i] = n; 3267 total_property_count += n; 3268 if (i < length - 1) { 3269 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 3270 } 3271 } 3272 3273 // Allocate an array with storage for all the property names. 3274 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count); 3275 3276 // Get the property names. 3277 jsproto = obj; 3278 int proto_with_hidden_properties = 0; 3279 for (int i = 0; i < length; i++) { 3280 jsproto->GetLocalPropertyNames(*names, 3281 i == 0 ? 0 : local_property_count[i - 1]); 3282 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) { 3283 proto_with_hidden_properties++; 3284 } 3285 if (i < length - 1) { 3286 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 3287 } 3288 } 3289 3290 // Filter out name of hidden propeties object. 3291 if (proto_with_hidden_properties > 0) { 3292 Handle<FixedArray> old_names = names; 3293 names = Factory::NewFixedArray( 3294 names->length() - proto_with_hidden_properties); 3295 int dest_pos = 0; 3296 for (int i = 0; i < total_property_count; i++) { 3297 Object* name = old_names->get(i); 3298 if (name == Heap::hidden_symbol()) { 3299 continue; 3300 } 3301 names->set(dest_pos++, name); 3302 } 3303 } 3304 3305 DeleteArray(local_property_count); 3306 return *Factory::NewJSArrayWithElements(names); 3307} 3308 3309 3310// Return the names of the local indexed properties. 3311// args[0]: object 3312static Object* Runtime_GetLocalElementNames(Arguments args) { 3313 HandleScope scope; 3314 ASSERT(args.length() == 1); 3315 if (!args[0]->IsJSObject()) { 3316 return Heap::undefined_value(); 3317 } 3318 CONVERT_ARG_CHECKED(JSObject, obj, 0); 3319 3320 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE)); 3321 Handle<FixedArray> names = Factory::NewFixedArray(n); 3322 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE)); 3323 return *Factory::NewJSArrayWithElements(names); 3324} 3325 3326 3327// Return information on whether an object has a named or indexed interceptor. 3328// args[0]: object 3329static Object* Runtime_GetInterceptorInfo(Arguments args) { 3330 HandleScope scope; 3331 ASSERT(args.length() == 1); 3332 if (!args[0]->IsJSObject()) { 3333 return Smi::FromInt(0); 3334 } 3335 CONVERT_ARG_CHECKED(JSObject, obj, 0); 3336 3337 int result = 0; 3338 if (obj->HasNamedInterceptor()) result |= 2; 3339 if (obj->HasIndexedInterceptor()) result |= 1; 3340 3341 return Smi::FromInt(result); 3342} 3343 3344 3345// Return property names from named interceptor. 3346// args[0]: object 3347static Object* Runtime_GetNamedInterceptorPropertyNames(Arguments args) { 3348 HandleScope scope; 3349 ASSERT(args.length() == 1); 3350 CONVERT_ARG_CHECKED(JSObject, obj, 0); 3351 3352 if (obj->HasNamedInterceptor()) { 3353 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj); 3354 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 3355 } 3356 return Heap::undefined_value(); 3357} 3358 3359 3360// Return element names from indexed interceptor. 3361// args[0]: object 3362static Object* Runtime_GetIndexedInterceptorElementNames(Arguments args) { 3363 HandleScope scope; 3364 ASSERT(args.length() == 1); 3365 CONVERT_ARG_CHECKED(JSObject, obj, 0); 3366 3367 if (obj->HasIndexedInterceptor()) { 3368 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj); 3369 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 3370 } 3371 return Heap::undefined_value(); 3372} 3373 3374 3375static Object* Runtime_LocalKeys(Arguments args) { 3376 ASSERT_EQ(args.length(), 1); 3377 CONVERT_CHECKED(JSObject, raw_object, args[0]); 3378 HandleScope scope; 3379 Handle<JSObject> object(raw_object); 3380 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object, 3381 LOCAL_ONLY); 3382 // Some fast paths through GetKeysInFixedArrayFor reuse a cached 3383 // property array and since the result is mutable we have to create 3384 // a fresh clone on each invocation. 3385 int length = contents->length(); 3386 Handle<FixedArray> copy = Factory::NewFixedArray(length); 3387 for (int i = 0; i < length; i++) { 3388 Object* entry = contents->get(i); 3389 if (entry->IsString()) { 3390 copy->set(i, entry); 3391 } else { 3392 ASSERT(entry->IsNumber()); 3393 HandleScope scope; 3394 Handle<Object> entry_handle(entry); 3395 Handle<Object> entry_str = Factory::NumberToString(entry_handle); 3396 copy->set(i, *entry_str); 3397 } 3398 } 3399 return *Factory::NewJSArrayWithElements(copy); 3400} 3401 3402 3403static Object* Runtime_GetArgumentsProperty(Arguments args) { 3404 NoHandleAllocation ha; 3405 ASSERT(args.length() == 1); 3406 3407 // Compute the frame holding the arguments. 3408 JavaScriptFrameIterator it; 3409 it.AdvanceToArgumentsFrame(); 3410 JavaScriptFrame* frame = it.frame(); 3411 3412 // Get the actual number of provided arguments. 3413 const uint32_t n = frame->GetProvidedParametersCount(); 3414 3415 // Try to convert the key to an index. If successful and within 3416 // index return the the argument from the frame. 3417 uint32_t index; 3418 if (Array::IndexFromObject(args[0], &index) && index < n) { 3419 return frame->GetParameter(index); 3420 } 3421 3422 // Convert the key to a string. 3423 HandleScope scope; 3424 bool exception = false; 3425 Handle<Object> converted = 3426 Execution::ToString(args.at<Object>(0), &exception); 3427 if (exception) return Failure::Exception(); 3428 Handle<String> key = Handle<String>::cast(converted); 3429 3430 // Try to convert the string key into an array index. 3431 if (key->AsArrayIndex(&index)) { 3432 if (index < n) { 3433 return frame->GetParameter(index); 3434 } else { 3435 return Top::initial_object_prototype()->GetElement(index); 3436 } 3437 } 3438 3439 // Handle special arguments properties. 3440 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n); 3441 if (key->Equals(Heap::callee_symbol())) return frame->function(); 3442 3443 // Lookup in the initial Object.prototype object. 3444 return Top::initial_object_prototype()->GetProperty(*key); 3445} 3446 3447 3448static Object* Runtime_ToFastProperties(Arguments args) { 3449 ASSERT(args.length() == 1); 3450 Handle<Object> object = args.at<Object>(0); 3451 if (object->IsJSObject()) { 3452 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 3453 js_object->TransformToFastProperties(0); 3454 } 3455 return *object; 3456} 3457 3458 3459static Object* Runtime_ToSlowProperties(Arguments args) { 3460 ASSERT(args.length() == 1); 3461 Handle<Object> object = args.at<Object>(0); 3462 if (object->IsJSObject()) { 3463 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 3464 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 3465 } 3466 return *object; 3467} 3468 3469 3470static Object* Runtime_ToBool(Arguments args) { 3471 NoHandleAllocation ha; 3472 ASSERT(args.length() == 1); 3473 3474 return args[0]->ToBoolean(); 3475} 3476 3477 3478// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). 3479// Possible optimizations: put the type string into the oddballs. 3480static Object* Runtime_Typeof(Arguments args) { 3481 NoHandleAllocation ha; 3482 3483 Object* obj = args[0]; 3484 if (obj->IsNumber()) return Heap::number_symbol(); 3485 HeapObject* heap_obj = HeapObject::cast(obj); 3486 3487 // typeof an undetectable object is 'undefined' 3488 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol(); 3489 3490 InstanceType instance_type = heap_obj->map()->instance_type(); 3491 if (instance_type < FIRST_NONSTRING_TYPE) { 3492 return Heap::string_symbol(); 3493 } 3494 3495 switch (instance_type) { 3496 case ODDBALL_TYPE: 3497 if (heap_obj->IsTrue() || heap_obj->IsFalse()) { 3498 return Heap::boolean_symbol(); 3499 } 3500 if (heap_obj->IsNull()) { 3501 return Heap::object_symbol(); 3502 } 3503 ASSERT(heap_obj->IsUndefined()); 3504 return Heap::undefined_symbol(); 3505 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE: 3506 return Heap::function_symbol(); 3507 default: 3508 // For any kind of object not handled above, the spec rule for 3509 // host objects gives that it is okay to return "object" 3510 return Heap::object_symbol(); 3511 } 3512} 3513 3514 3515static Object* Runtime_StringToNumber(Arguments args) { 3516 NoHandleAllocation ha; 3517 ASSERT(args.length() == 1); 3518 CONVERT_CHECKED(String, subject, args[0]); 3519 subject->TryFlattenIfNotFlat(); 3520 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); 3521} 3522 3523 3524static Object* Runtime_StringFromCharCodeArray(Arguments args) { 3525 NoHandleAllocation ha; 3526 ASSERT(args.length() == 1); 3527 3528 CONVERT_CHECKED(JSArray, codes, args[0]); 3529 int length = Smi::cast(codes->length())->value(); 3530 3531 // Check if the string can be ASCII. 3532 int i; 3533 for (i = 0; i < length; i++) { 3534 Object* element = codes->GetElement(i); 3535 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); 3536 if ((chr & 0xffff) > String::kMaxAsciiCharCode) 3537 break; 3538 } 3539 3540 Object* object = NULL; 3541 if (i == length) { // The string is ASCII. 3542 object = Heap::AllocateRawAsciiString(length); 3543 } else { // The string is not ASCII. 3544 object = Heap::AllocateRawTwoByteString(length); 3545 } 3546 3547 if (object->IsFailure()) return object; 3548 String* result = String::cast(object); 3549 for (int i = 0; i < length; i++) { 3550 Object* element = codes->GetElement(i); 3551 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); 3552 result->Set(i, chr & 0xffff); 3553 } 3554 return result; 3555} 3556 3557 3558// kNotEscaped is generated by the following: 3559// 3560// #!/bin/perl 3561// for (my $i = 0; $i < 256; $i++) { 3562// print "\n" if $i % 16 == 0; 3563// my $c = chr($i); 3564// my $escaped = 1; 3565// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#; 3566// print $escaped ? "0, " : "1, "; 3567// } 3568 3569 3570static bool IsNotEscaped(uint16_t character) { 3571 // Only for 8 bit characters, the rest are always escaped (in a different way) 3572 ASSERT(character < 256); 3573 static const char kNotEscaped[256] = { 3574 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3575 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3576 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 3577 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 3578 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3579 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 3580 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3581 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 3582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3583 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3584 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3585 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3586 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3587 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3588 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3590 }; 3591 return kNotEscaped[character] != 0; 3592} 3593 3594 3595static Object* Runtime_URIEscape(Arguments args) { 3596 const char hex_chars[] = "0123456789ABCDEF"; 3597 NoHandleAllocation ha; 3598 ASSERT(args.length() == 1); 3599 CONVERT_CHECKED(String, source, args[0]); 3600 3601 source->TryFlattenIfNotFlat(); 3602 3603 int escaped_length = 0; 3604 int length = source->length(); 3605 { 3606 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); 3607 buffer->Reset(source); 3608 while (buffer->has_more()) { 3609 uint16_t character = buffer->GetNext(); 3610 if (character >= 256) { 3611 escaped_length += 6; 3612 } else if (IsNotEscaped(character)) { 3613 escaped_length++; 3614 } else { 3615 escaped_length += 3; 3616 } 3617 // We don't allow strings that are longer than a maximal length. 3618 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow. 3619 if (escaped_length > String::kMaxLength) { 3620 Top::context()->mark_out_of_memory(); 3621 return Failure::OutOfMemoryException(); 3622 } 3623 } 3624 } 3625 // No length change implies no change. Return original string if no change. 3626 if (escaped_length == length) { 3627 return source; 3628 } 3629 Object* o = Heap::AllocateRawAsciiString(escaped_length); 3630 if (o->IsFailure()) return o; 3631 String* destination = String::cast(o); 3632 int dest_position = 0; 3633 3634 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); 3635 buffer->Rewind(); 3636 while (buffer->has_more()) { 3637 uint16_t chr = buffer->GetNext(); 3638 if (chr >= 256) { 3639 destination->Set(dest_position, '%'); 3640 destination->Set(dest_position+1, 'u'); 3641 destination->Set(dest_position+2, hex_chars[chr >> 12]); 3642 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); 3643 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); 3644 destination->Set(dest_position+5, hex_chars[chr & 0xf]); 3645 dest_position += 6; 3646 } else if (IsNotEscaped(chr)) { 3647 destination->Set(dest_position, chr); 3648 dest_position++; 3649 } else { 3650 destination->Set(dest_position, '%'); 3651 destination->Set(dest_position+1, hex_chars[chr >> 4]); 3652 destination->Set(dest_position+2, hex_chars[chr & 0xf]); 3653 dest_position += 3; 3654 } 3655 } 3656 return destination; 3657} 3658 3659 3660static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { 3661 static const signed char kHexValue['g'] = { 3662 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3663 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3664 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3665 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 3666 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3667 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3668 -1, 10, 11, 12, 13, 14, 15 }; 3669 3670 if (character1 > 'f') return -1; 3671 int hi = kHexValue[character1]; 3672 if (hi == -1) return -1; 3673 if (character2 > 'f') return -1; 3674 int lo = kHexValue[character2]; 3675 if (lo == -1) return -1; 3676 return (hi << 4) + lo; 3677} 3678 3679 3680static inline int Unescape(String* source, 3681 int i, 3682 int length, 3683 int* step) { 3684 uint16_t character = source->Get(i); 3685 int32_t hi = 0; 3686 int32_t lo = 0; 3687 if (character == '%' && 3688 i <= length - 6 && 3689 source->Get(i + 1) == 'u' && 3690 (hi = TwoDigitHex(source->Get(i + 2), 3691 source->Get(i + 3))) != -1 && 3692 (lo = TwoDigitHex(source->Get(i + 4), 3693 source->Get(i + 5))) != -1) { 3694 *step = 6; 3695 return (hi << 8) + lo; 3696 } else if (character == '%' && 3697 i <= length - 3 && 3698 (lo = TwoDigitHex(source->Get(i + 1), 3699 source->Get(i + 2))) != -1) { 3700 *step = 3; 3701 return lo; 3702 } else { 3703 *step = 1; 3704 return character; 3705 } 3706} 3707 3708 3709static Object* Runtime_URIUnescape(Arguments args) { 3710 NoHandleAllocation ha; 3711 ASSERT(args.length() == 1); 3712 CONVERT_CHECKED(String, source, args[0]); 3713 3714 source->TryFlattenIfNotFlat(); 3715 3716 bool ascii = true; 3717 int length = source->length(); 3718 3719 int unescaped_length = 0; 3720 for (int i = 0; i < length; unescaped_length++) { 3721 int step; 3722 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) { 3723 ascii = false; 3724 } 3725 i += step; 3726 } 3727 3728 // No length change implies no change. Return original string if no change. 3729 if (unescaped_length == length) 3730 return source; 3731 3732 Object* o = ascii ? 3733 Heap::AllocateRawAsciiString(unescaped_length) : 3734 Heap::AllocateRawTwoByteString(unescaped_length); 3735 if (o->IsFailure()) return o; 3736 String* destination = String::cast(o); 3737 3738 int dest_position = 0; 3739 for (int i = 0; i < length; dest_position++) { 3740 int step; 3741 destination->Set(dest_position, Unescape(source, i, length, &step)); 3742 i += step; 3743 } 3744 return destination; 3745} 3746 3747 3748static Object* Runtime_StringParseInt(Arguments args) { 3749 NoHandleAllocation ha; 3750 3751 CONVERT_CHECKED(String, s, args[0]); 3752 CONVERT_SMI_CHECKED(radix, args[1]); 3753 3754 s->TryFlattenIfNotFlat(); 3755 3756 int len = s->length(); 3757 int i; 3758 3759 // Skip leading white space. 3760 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ; 3761 if (i == len) return Heap::nan_value(); 3762 3763 // Compute the sign (default to +). 3764 int sign = 1; 3765 if (s->Get(i) == '-') { 3766 sign = -1; 3767 i++; 3768 } else if (s->Get(i) == '+') { 3769 i++; 3770 } 3771 3772 // Compute the radix if 0. 3773 if (radix == 0) { 3774 radix = 10; 3775 if (i < len && s->Get(i) == '0') { 3776 radix = 8; 3777 if (i + 1 < len) { 3778 int c = s->Get(i + 1); 3779 if (c == 'x' || c == 'X') { 3780 radix = 16; 3781 i += 2; 3782 } 3783 } 3784 } 3785 } else if (radix == 16) { 3786 // Allow 0x or 0X prefix if radix is 16. 3787 if (i + 1 < len && s->Get(i) == '0') { 3788 int c = s->Get(i + 1); 3789 if (c == 'x' || c == 'X') i += 2; 3790 } 3791 } 3792 3793 RUNTIME_ASSERT(2 <= radix && radix <= 36); 3794 double value; 3795 int end_index = StringToInt(s, i, radix, &value); 3796 if (end_index != i) { 3797 return Heap::NumberFromDouble(sign * value); 3798 } 3799 return Heap::nan_value(); 3800} 3801 3802 3803static Object* Runtime_StringParseFloat(Arguments args) { 3804 NoHandleAllocation ha; 3805 CONVERT_CHECKED(String, str, args[0]); 3806 3807 // ECMA-262 section 15.1.2.3, empty string is NaN 3808 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value()); 3809 3810 // Create a number object from the value. 3811 return Heap::NumberFromDouble(value); 3812} 3813 3814 3815static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; 3816static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; 3817 3818 3819template <class Converter> 3820static Object* ConvertCaseHelper(String* s, 3821 int length, 3822 int input_string_length, 3823 unibrow::Mapping<Converter, 128>* mapping) { 3824 // We try this twice, once with the assumption that the result is no longer 3825 // than the input and, if that assumption breaks, again with the exact 3826 // length. This may not be pretty, but it is nicer than what was here before 3827 // and I hereby claim my vaffel-is. 3828 // 3829 // Allocate the resulting string. 3830 // 3831 // NOTE: This assumes that the upper/lower case of an ascii 3832 // character is also ascii. This is currently the case, but it 3833 // might break in the future if we implement more context and locale 3834 // dependent upper/lower conversions. 3835 Object* o = s->IsAsciiRepresentation() 3836 ? Heap::AllocateRawAsciiString(length) 3837 : Heap::AllocateRawTwoByteString(length); 3838 if (o->IsFailure()) return o; 3839 String* result = String::cast(o); 3840 bool has_changed_character = false; 3841 3842 // Convert all characters to upper case, assuming that they will fit 3843 // in the buffer 3844 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); 3845 buffer->Reset(s); 3846 unibrow::uchar chars[Converter::kMaxWidth]; 3847 // We can assume that the string is not empty 3848 uc32 current = buffer->GetNext(); 3849 for (int i = 0; i < length;) { 3850 bool has_next = buffer->has_more(); 3851 uc32 next = has_next ? buffer->GetNext() : 0; 3852 int char_length = mapping->get(current, next, chars); 3853 if (char_length == 0) { 3854 // The case conversion of this character is the character itself. 3855 result->Set(i, current); 3856 i++; 3857 } else if (char_length == 1) { 3858 // Common case: converting the letter resulted in one character. 3859 ASSERT(static_cast<uc32>(chars[0]) != current); 3860 result->Set(i, chars[0]); 3861 has_changed_character = true; 3862 i++; 3863 } else if (length == input_string_length) { 3864 // We've assumed that the result would be as long as the 3865 // input but here is a character that converts to several 3866 // characters. No matter, we calculate the exact length 3867 // of the result and try the whole thing again. 3868 // 3869 // Note that this leaves room for optimization. We could just 3870 // memcpy what we already have to the result string. Also, 3871 // the result string is the last object allocated we could 3872 // "realloc" it and probably, in the vast majority of cases, 3873 // extend the existing string to be able to hold the full 3874 // result. 3875 int next_length = 0; 3876 if (has_next) { 3877 next_length = mapping->get(next, 0, chars); 3878 if (next_length == 0) next_length = 1; 3879 } 3880 int current_length = i + char_length + next_length; 3881 while (buffer->has_more()) { 3882 current = buffer->GetNext(); 3883 // NOTE: we use 0 as the next character here because, while 3884 // the next character may affect what a character converts to, 3885 // it does not in any case affect the length of what it convert 3886 // to. 3887 int char_length = mapping->get(current, 0, chars); 3888 if (char_length == 0) char_length = 1; 3889 current_length += char_length; 3890 if (current_length > Smi::kMaxValue) { 3891 Top::context()->mark_out_of_memory(); 3892 return Failure::OutOfMemoryException(); 3893 } 3894 } 3895 // Try again with the real length. 3896 return Smi::FromInt(current_length); 3897 } else { 3898 for (int j = 0; j < char_length; j++) { 3899 result->Set(i, chars[j]); 3900 i++; 3901 } 3902 has_changed_character = true; 3903 } 3904 current = next; 3905 } 3906 if (has_changed_character) { 3907 return result; 3908 } else { 3909 // If we didn't actually change anything in doing the conversion 3910 // we simple return the result and let the converted string 3911 // become garbage; there is no reason to keep two identical strings 3912 // alive. 3913 return s; 3914 } 3915} 3916 3917 3918template <class Converter> 3919static Object* ConvertCase(Arguments args, 3920 unibrow::Mapping<Converter, 128>* mapping) { 3921 NoHandleAllocation ha; 3922 3923 CONVERT_CHECKED(String, s, args[0]); 3924 s->TryFlattenIfNotFlat(); 3925 3926 int input_string_length = s->length(); 3927 // Assume that the string is not empty; we need this assumption later 3928 if (input_string_length == 0) return s; 3929 int length = input_string_length; 3930 3931 Object* answer = ConvertCaseHelper(s, length, length, mapping); 3932 if (answer->IsSmi()) { 3933 // Retry with correct length. 3934 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping); 3935 } 3936 return answer; // This may be a failure. 3937} 3938 3939 3940static Object* Runtime_StringToLowerCase(Arguments args) { 3941 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping); 3942} 3943 3944 3945static Object* Runtime_StringToUpperCase(Arguments args) { 3946 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping); 3947} 3948 3949static inline bool IsTrimWhiteSpace(unibrow::uchar c) { 3950 return unibrow::WhiteSpace::Is(c) || c == 0x200b; 3951} 3952 3953static Object* Runtime_StringTrim(Arguments args) { 3954 NoHandleAllocation ha; 3955 ASSERT(args.length() == 3); 3956 3957 CONVERT_CHECKED(String, s, args[0]); 3958 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]); 3959 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]); 3960 3961 s->TryFlattenIfNotFlat(); 3962 int length = s->length(); 3963 3964 int left = 0; 3965 if (trimLeft) { 3966 while (left < length && IsTrimWhiteSpace(s->Get(left))) { 3967 left++; 3968 } 3969 } 3970 3971 int right = length; 3972 if (trimRight) { 3973 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { 3974 right--; 3975 } 3976 } 3977 return s->SubString(left, right); 3978} 3979 3980bool Runtime::IsUpperCaseChar(uint16_t ch) { 3981 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; 3982 int char_length = to_upper_mapping.get(ch, 0, chars); 3983 return char_length == 0; 3984} 3985 3986 3987static Object* Runtime_NumberToString(Arguments args) { 3988 NoHandleAllocation ha; 3989 ASSERT(args.length() == 1); 3990 3991 Object* number = args[0]; 3992 RUNTIME_ASSERT(number->IsNumber()); 3993 3994 return Heap::NumberToString(number); 3995} 3996 3997 3998static Object* Runtime_NumberToInteger(Arguments args) { 3999 NoHandleAllocation ha; 4000 ASSERT(args.length() == 1); 4001 4002 Object* obj = args[0]; 4003 if (obj->IsSmi()) return obj; 4004 CONVERT_DOUBLE_CHECKED(number, obj); 4005 return Heap::NumberFromDouble(DoubleToInteger(number)); 4006} 4007 4008 4009static Object* Runtime_NumberToJSUint32(Arguments args) { 4010 NoHandleAllocation ha; 4011 ASSERT(args.length() == 1); 4012 4013 Object* obj = args[0]; 4014 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj; 4015 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj); 4016 return Heap::NumberFromUint32(number); 4017} 4018 4019 4020static Object* Runtime_NumberToJSInt32(Arguments args) { 4021 NoHandleAllocation ha; 4022 ASSERT(args.length() == 1); 4023 4024 Object* obj = args[0]; 4025 if (obj->IsSmi()) return obj; 4026 CONVERT_DOUBLE_CHECKED(number, obj); 4027 return Heap::NumberFromInt32(DoubleToInt32(number)); 4028} 4029 4030 4031// Converts a Number to a Smi, if possible. Returns NaN if the number is not 4032// a small integer. 4033static Object* Runtime_NumberToSmi(Arguments args) { 4034 NoHandleAllocation ha; 4035 ASSERT(args.length() == 1); 4036 4037 Object* obj = args[0]; 4038 if (obj->IsSmi()) { 4039 return obj; 4040 } 4041 if (obj->IsHeapNumber()) { 4042 double value = HeapNumber::cast(obj)->value(); 4043 int int_value = FastD2I(value); 4044 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { 4045 return Smi::FromInt(int_value); 4046 } 4047 } 4048 return Heap::nan_value(); 4049} 4050 4051 4052static Object* Runtime_NumberAdd(Arguments args) { 4053 NoHandleAllocation ha; 4054 ASSERT(args.length() == 2); 4055 4056 CONVERT_DOUBLE_CHECKED(x, args[0]); 4057 CONVERT_DOUBLE_CHECKED(y, args[1]); 4058 return Heap::AllocateHeapNumber(x + y); 4059} 4060 4061 4062static Object* Runtime_NumberSub(Arguments args) { 4063 NoHandleAllocation ha; 4064 ASSERT(args.length() == 2); 4065 4066 CONVERT_DOUBLE_CHECKED(x, args[0]); 4067 CONVERT_DOUBLE_CHECKED(y, args[1]); 4068 return Heap::AllocateHeapNumber(x - y); 4069} 4070 4071 4072static Object* Runtime_NumberMul(Arguments args) { 4073 NoHandleAllocation ha; 4074 ASSERT(args.length() == 2); 4075 4076 CONVERT_DOUBLE_CHECKED(x, args[0]); 4077 CONVERT_DOUBLE_CHECKED(y, args[1]); 4078 return Heap::AllocateHeapNumber(x * y); 4079} 4080 4081 4082static Object* Runtime_NumberUnaryMinus(Arguments args) { 4083 NoHandleAllocation ha; 4084 ASSERT(args.length() == 1); 4085 4086 CONVERT_DOUBLE_CHECKED(x, args[0]); 4087 return Heap::AllocateHeapNumber(-x); 4088} 4089 4090 4091static Object* Runtime_NumberDiv(Arguments args) { 4092 NoHandleAllocation ha; 4093 ASSERT(args.length() == 2); 4094 4095 CONVERT_DOUBLE_CHECKED(x, args[0]); 4096 CONVERT_DOUBLE_CHECKED(y, args[1]); 4097 return Heap::NewNumberFromDouble(x / y); 4098} 4099 4100 4101static Object* Runtime_NumberMod(Arguments args) { 4102 NoHandleAllocation ha; 4103 ASSERT(args.length() == 2); 4104 4105 CONVERT_DOUBLE_CHECKED(x, args[0]); 4106 CONVERT_DOUBLE_CHECKED(y, args[1]); 4107 4108 x = modulo(x, y); 4109 // NewNumberFromDouble may return a Smi instead of a Number object 4110 return Heap::NewNumberFromDouble(x); 4111} 4112 4113 4114static Object* Runtime_StringAdd(Arguments args) { 4115 NoHandleAllocation ha; 4116 ASSERT(args.length() == 2); 4117 CONVERT_CHECKED(String, str1, args[0]); 4118 CONVERT_CHECKED(String, str2, args[1]); 4119 Counters::string_add_runtime.Increment(); 4120 return Heap::AllocateConsString(str1, str2); 4121} 4122 4123 4124template<typename sinkchar> 4125static inline void StringBuilderConcatHelper(String* special, 4126 sinkchar* sink, 4127 FixedArray* fixed_array, 4128 int array_length) { 4129 int position = 0; 4130 for (int i = 0; i < array_length; i++) { 4131 Object* element = fixed_array->get(i); 4132 if (element->IsSmi()) { 4133 // Smi encoding of position and length. 4134 int encoded_slice = Smi::cast(element)->value(); 4135 int pos; 4136 int len; 4137 if (encoded_slice > 0) { 4138 // Position and length encoded in one smi. 4139 pos = StringBuilderSubstringPosition::decode(encoded_slice); 4140 len = StringBuilderSubstringLength::decode(encoded_slice); 4141 } else { 4142 // Position and length encoded in two smis. 4143 Object* obj = fixed_array->get(++i); 4144 ASSERT(obj->IsSmi()); 4145 pos = Smi::cast(obj)->value(); 4146 len = -encoded_slice; 4147 } 4148 String::WriteToFlat(special, 4149 sink + position, 4150 pos, 4151 pos + len); 4152 position += len; 4153 } else { 4154 String* string = String::cast(element); 4155 int element_length = string->length(); 4156 String::WriteToFlat(string, sink + position, 0, element_length); 4157 position += element_length; 4158 } 4159 } 4160} 4161 4162 4163static Object* Runtime_StringBuilderConcat(Arguments args) { 4164 NoHandleAllocation ha; 4165 ASSERT(args.length() == 3); 4166 CONVERT_CHECKED(JSArray, array, args[0]); 4167 if (!args[1]->IsSmi()) { 4168 Top::context()->mark_out_of_memory(); 4169 return Failure::OutOfMemoryException(); 4170 } 4171 int array_length = Smi::cast(args[1])->value(); 4172 CONVERT_CHECKED(String, special, args[2]); 4173 4174 // This assumption is used by the slice encoding in one or two smis. 4175 ASSERT(Smi::kMaxValue >= String::kMaxLength); 4176 4177 int special_length = special->length(); 4178 if (!array->HasFastElements()) { 4179 return Top::Throw(Heap::illegal_argument_symbol()); 4180 } 4181 FixedArray* fixed_array = FixedArray::cast(array->elements()); 4182 if (fixed_array->length() < array_length) { 4183 array_length = fixed_array->length(); 4184 } 4185 4186 if (array_length == 0) { 4187 return Heap::empty_string(); 4188 } else if (array_length == 1) { 4189 Object* first = fixed_array->get(0); 4190 if (first->IsString()) return first; 4191 } 4192 4193 bool ascii = special->IsAsciiRepresentation(); 4194 int position = 0; 4195 int increment = 0; 4196 for (int i = 0; i < array_length; i++) { 4197 Object* elt = fixed_array->get(i); 4198 if (elt->IsSmi()) { 4199 // Smi encoding of position and length. 4200 int len = Smi::cast(elt)->value(); 4201 if (len > 0) { 4202 // Position and length encoded in one smi. 4203 int pos = len >> 11; 4204 len &= 0x7ff; 4205 if (pos + len > special_length) { 4206 return Top::Throw(Heap::illegal_argument_symbol()); 4207 } 4208 increment = len; 4209 } else { 4210 // Position and length encoded in two smis. 4211 increment = (-len); 4212 // Get the position and check that it is also a smi. 4213 i++; 4214 if (i >= array_length) { 4215 return Top::Throw(Heap::illegal_argument_symbol()); 4216 } 4217 Object* pos = fixed_array->get(i); 4218 if (!pos->IsSmi()) { 4219 return Top::Throw(Heap::illegal_argument_symbol()); 4220 } 4221 } 4222 } else if (elt->IsString()) { 4223 String* element = String::cast(elt); 4224 int element_length = element->length(); 4225 increment = element_length; 4226 if (ascii && !element->IsAsciiRepresentation()) { 4227 ascii = false; 4228 } 4229 } else { 4230 return Top::Throw(Heap::illegal_argument_symbol()); 4231 } 4232 if (increment > String::kMaxLength - position) { 4233 Top::context()->mark_out_of_memory(); 4234 return Failure::OutOfMemoryException(); 4235 } 4236 position += increment; 4237 } 4238 4239 int length = position; 4240 Object* object; 4241 4242 if (ascii) { 4243 object = Heap::AllocateRawAsciiString(length); 4244 if (object->IsFailure()) return object; 4245 SeqAsciiString* answer = SeqAsciiString::cast(object); 4246 StringBuilderConcatHelper(special, 4247 answer->GetChars(), 4248 fixed_array, 4249 array_length); 4250 return answer; 4251 } else { 4252 object = Heap::AllocateRawTwoByteString(length); 4253 if (object->IsFailure()) return object; 4254 SeqTwoByteString* answer = SeqTwoByteString::cast(object); 4255 StringBuilderConcatHelper(special, 4256 answer->GetChars(), 4257 fixed_array, 4258 array_length); 4259 return answer; 4260 } 4261} 4262 4263 4264static Object* Runtime_NumberOr(Arguments args) { 4265 NoHandleAllocation ha; 4266 ASSERT(args.length() == 2); 4267 4268 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 4269 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 4270 return Heap::NumberFromInt32(x | y); 4271} 4272 4273 4274static Object* Runtime_NumberAnd(Arguments args) { 4275 NoHandleAllocation ha; 4276 ASSERT(args.length() == 2); 4277 4278 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 4279 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 4280 return Heap::NumberFromInt32(x & y); 4281} 4282 4283 4284static Object* Runtime_NumberXor(Arguments args) { 4285 NoHandleAllocation ha; 4286 ASSERT(args.length() == 2); 4287 4288 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 4289 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 4290 return Heap::NumberFromInt32(x ^ y); 4291} 4292 4293 4294static Object* Runtime_NumberNot(Arguments args) { 4295 NoHandleAllocation ha; 4296 ASSERT(args.length() == 1); 4297 4298 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 4299 return Heap::NumberFromInt32(~x); 4300} 4301 4302 4303static Object* Runtime_NumberShl(Arguments args) { 4304 NoHandleAllocation ha; 4305 ASSERT(args.length() == 2); 4306 4307 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 4308 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 4309 return Heap::NumberFromInt32(x << (y & 0x1f)); 4310} 4311 4312 4313static Object* Runtime_NumberShr(Arguments args) { 4314 NoHandleAllocation ha; 4315 ASSERT(args.length() == 2); 4316 4317 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); 4318 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 4319 return Heap::NumberFromUint32(x >> (y & 0x1f)); 4320} 4321 4322 4323static Object* Runtime_NumberSar(Arguments args) { 4324 NoHandleAllocation ha; 4325 ASSERT(args.length() == 2); 4326 4327 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 4328 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 4329 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f)); 4330} 4331 4332 4333static Object* Runtime_NumberEquals(Arguments args) { 4334 NoHandleAllocation ha; 4335 ASSERT(args.length() == 2); 4336 4337 CONVERT_DOUBLE_CHECKED(x, args[0]); 4338 CONVERT_DOUBLE_CHECKED(y, args[1]); 4339 if (isnan(x)) return Smi::FromInt(NOT_EQUAL); 4340 if (isnan(y)) return Smi::FromInt(NOT_EQUAL); 4341 if (x == y) return Smi::FromInt(EQUAL); 4342 Object* result; 4343 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { 4344 result = Smi::FromInt(EQUAL); 4345 } else { 4346 result = Smi::FromInt(NOT_EQUAL); 4347 } 4348 return result; 4349} 4350 4351 4352static Object* Runtime_StringEquals(Arguments args) { 4353 NoHandleAllocation ha; 4354 ASSERT(args.length() == 2); 4355 4356 CONVERT_CHECKED(String, x, args[0]); 4357 CONVERT_CHECKED(String, y, args[1]); 4358 4359 bool not_equal = !x->Equals(y); 4360 // This is slightly convoluted because the value that signifies 4361 // equality is 0 and inequality is 1 so we have to negate the result 4362 // from String::Equals. 4363 ASSERT(not_equal == 0 || not_equal == 1); 4364 STATIC_CHECK(EQUAL == 0); 4365 STATIC_CHECK(NOT_EQUAL == 1); 4366 return Smi::FromInt(not_equal); 4367} 4368 4369 4370static Object* Runtime_NumberCompare(Arguments args) { 4371 NoHandleAllocation ha; 4372 ASSERT(args.length() == 3); 4373 4374 CONVERT_DOUBLE_CHECKED(x, args[0]); 4375 CONVERT_DOUBLE_CHECKED(y, args[1]); 4376 if (isnan(x) || isnan(y)) return args[2]; 4377 if (x == y) return Smi::FromInt(EQUAL); 4378 if (isless(x, y)) return Smi::FromInt(LESS); 4379 return Smi::FromInt(GREATER); 4380} 4381 4382 4383// Compare two Smis as if they were converted to strings and then 4384// compared lexicographically. 4385static Object* Runtime_SmiLexicographicCompare(Arguments args) { 4386 NoHandleAllocation ha; 4387 ASSERT(args.length() == 2); 4388 4389 // Arrays for the individual characters of the two Smis. Smis are 4390 // 31 bit integers and 10 decimal digits are therefore enough. 4391 static int x_elms[10]; 4392 static int y_elms[10]; 4393 4394 // Extract the integer values from the Smis. 4395 CONVERT_CHECKED(Smi, x, args[0]); 4396 CONVERT_CHECKED(Smi, y, args[1]); 4397 int x_value = x->value(); 4398 int y_value = y->value(); 4399 4400 // If the integers are equal so are the string representations. 4401 if (x_value == y_value) return Smi::FromInt(EQUAL); 4402 4403 // If one of the integers are zero the normal integer order is the 4404 // same as the lexicographic order of the string representations. 4405 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value); 4406 4407 // If only one of the integers is negative the negative number is 4408 // smallest because the char code of '-' is less than the char code 4409 // of any digit. Otherwise, we make both values positive. 4410 if (x_value < 0 || y_value < 0) { 4411 if (y_value >= 0) return Smi::FromInt(LESS); 4412 if (x_value >= 0) return Smi::FromInt(GREATER); 4413 x_value = -x_value; 4414 y_value = -y_value; 4415 } 4416 4417 // Convert the integers to arrays of their decimal digits. 4418 int x_index = 0; 4419 int y_index = 0; 4420 while (x_value > 0) { 4421 x_elms[x_index++] = x_value % 10; 4422 x_value /= 10; 4423 } 4424 while (y_value > 0) { 4425 y_elms[y_index++] = y_value % 10; 4426 y_value /= 10; 4427 } 4428 4429 // Loop through the arrays of decimal digits finding the first place 4430 // where they differ. 4431 while (--x_index >= 0 && --y_index >= 0) { 4432 int diff = x_elms[x_index] - y_elms[y_index]; 4433 if (diff != 0) return Smi::FromInt(diff); 4434 } 4435 4436 // If one array is a suffix of the other array, the longest array is 4437 // the representation of the largest of the Smis in the 4438 // lexicographic ordering. 4439 return Smi::FromInt(x_index - y_index); 4440} 4441 4442 4443static Object* Runtime_StringCompare(Arguments args) { 4444 NoHandleAllocation ha; 4445 ASSERT(args.length() == 2); 4446 4447 CONVERT_CHECKED(String, x, args[0]); 4448 CONVERT_CHECKED(String, y, args[1]); 4449 4450 Counters::string_compare_runtime.Increment(); 4451 4452 // A few fast case tests before we flatten. 4453 if (x == y) return Smi::FromInt(EQUAL); 4454 if (y->length() == 0) { 4455 if (x->length() == 0) return Smi::FromInt(EQUAL); 4456 return Smi::FromInt(GREATER); 4457 } else if (x->length() == 0) { 4458 return Smi::FromInt(LESS); 4459 } 4460 4461 int d = x->Get(0) - y->Get(0); 4462 if (d < 0) return Smi::FromInt(LESS); 4463 else if (d > 0) return Smi::FromInt(GREATER); 4464 4465 x->TryFlattenIfNotFlat(); 4466 y->TryFlattenIfNotFlat(); 4467 4468 static StringInputBuffer bufx; 4469 static StringInputBuffer bufy; 4470 bufx.Reset(x); 4471 bufy.Reset(y); 4472 while (bufx.has_more() && bufy.has_more()) { 4473 int d = bufx.GetNext() - bufy.GetNext(); 4474 if (d < 0) return Smi::FromInt(LESS); 4475 else if (d > 0) return Smi::FromInt(GREATER); 4476 } 4477 4478 // x is (non-trivial) prefix of y: 4479 if (bufy.has_more()) return Smi::FromInt(LESS); 4480 // y is prefix of x: 4481 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL); 4482} 4483 4484 4485static Object* Runtime_Math_abs(Arguments args) { 4486 NoHandleAllocation ha; 4487 ASSERT(args.length() == 1); 4488 4489 CONVERT_DOUBLE_CHECKED(x, args[0]); 4490 return Heap::AllocateHeapNumber(fabs(x)); 4491} 4492 4493 4494static Object* Runtime_Math_acos(Arguments args) { 4495 NoHandleAllocation ha; 4496 ASSERT(args.length() == 1); 4497 4498 CONVERT_DOUBLE_CHECKED(x, args[0]); 4499 return TranscendentalCache::Get(TranscendentalCache::ACOS, x); 4500} 4501 4502 4503static Object* Runtime_Math_asin(Arguments args) { 4504 NoHandleAllocation ha; 4505 ASSERT(args.length() == 1); 4506 4507 CONVERT_DOUBLE_CHECKED(x, args[0]); 4508 return TranscendentalCache::Get(TranscendentalCache::ASIN, x); 4509} 4510 4511 4512static Object* Runtime_Math_atan(Arguments args) { 4513 NoHandleAllocation ha; 4514 ASSERT(args.length() == 1); 4515 4516 CONVERT_DOUBLE_CHECKED(x, args[0]); 4517 return TranscendentalCache::Get(TranscendentalCache::ATAN, x); 4518} 4519 4520 4521static Object* Runtime_Math_atan2(Arguments args) { 4522 NoHandleAllocation ha; 4523 ASSERT(args.length() == 2); 4524 4525 CONVERT_DOUBLE_CHECKED(x, args[0]); 4526 CONVERT_DOUBLE_CHECKED(y, args[1]); 4527 double result; 4528 if (isinf(x) && isinf(y)) { 4529 // Make sure that the result in case of two infinite arguments 4530 // is a multiple of Pi / 4. The sign of the result is determined 4531 // by the first argument (x) and the sign of the second argument 4532 // determines the multiplier: one or three. 4533 static double kPiDividedBy4 = 0.78539816339744830962; 4534 int multiplier = (x < 0) ? -1 : 1; 4535 if (y < 0) multiplier *= 3; 4536 result = multiplier * kPiDividedBy4; 4537 } else { 4538 result = atan2(x, y); 4539 } 4540 return Heap::AllocateHeapNumber(result); 4541} 4542 4543 4544static Object* Runtime_Math_ceil(Arguments args) { 4545 NoHandleAllocation ha; 4546 ASSERT(args.length() == 1); 4547 4548 CONVERT_DOUBLE_CHECKED(x, args[0]); 4549 return Heap::NumberFromDouble(ceiling(x)); 4550} 4551 4552 4553static Object* Runtime_Math_cos(Arguments args) { 4554 NoHandleAllocation ha; 4555 ASSERT(args.length() == 1); 4556 4557 CONVERT_DOUBLE_CHECKED(x, args[0]); 4558 return TranscendentalCache::Get(TranscendentalCache::COS, x); 4559} 4560 4561 4562static Object* Runtime_Math_exp(Arguments args) { 4563 NoHandleAllocation ha; 4564 ASSERT(args.length() == 1); 4565 4566 CONVERT_DOUBLE_CHECKED(x, args[0]); 4567 return TranscendentalCache::Get(TranscendentalCache::EXP, x); 4568} 4569 4570 4571static Object* Runtime_Math_floor(Arguments args) { 4572 NoHandleAllocation ha; 4573 ASSERT(args.length() == 1); 4574 4575 CONVERT_DOUBLE_CHECKED(x, args[0]); 4576 return Heap::NumberFromDouble(floor(x)); 4577} 4578 4579 4580static Object* Runtime_Math_log(Arguments args) { 4581 NoHandleAllocation ha; 4582 ASSERT(args.length() == 1); 4583 4584 CONVERT_DOUBLE_CHECKED(x, args[0]); 4585 return TranscendentalCache::Get(TranscendentalCache::LOG, x); 4586} 4587 4588 4589// Helper function to compute x^y, where y is known to be an 4590// integer. Uses binary decomposition to limit the number of 4591// multiplications; see the discussion in "Hacker's Delight" by Henry 4592// S. Warren, Jr., figure 11-6, page 213. 4593static double powi(double x, int y) { 4594 ASSERT(y != kMinInt); 4595 unsigned n = (y < 0) ? -y : y; 4596 double m = x; 4597 double p = 1; 4598 while (true) { 4599 if ((n & 1) != 0) p *= m; 4600 n >>= 1; 4601 if (n == 0) { 4602 if (y < 0) { 4603 // Unfortunately, we have to be careful when p has reached 4604 // infinity in the computation, because sometimes the higher 4605 // internal precision in the pow() implementation would have 4606 // given us a finite p. This happens very rarely. 4607 double result = 1.0 / p; 4608 return (result == 0 && isinf(p)) 4609 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int). 4610 : result; 4611 } else { 4612 return p; 4613 } 4614 } 4615 m *= m; 4616 } 4617} 4618 4619 4620static Object* Runtime_Math_pow(Arguments args) { 4621 NoHandleAllocation ha; 4622 ASSERT(args.length() == 2); 4623 4624 CONVERT_DOUBLE_CHECKED(x, args[0]); 4625 4626 // If the second argument is a smi, it is much faster to call the 4627 // custom powi() function than the generic pow(). 4628 if (args[1]->IsSmi()) { 4629 int y = Smi::cast(args[1])->value(); 4630 return Heap::AllocateHeapNumber(powi(x, y)); 4631 } 4632 4633 CONVERT_DOUBLE_CHECKED(y, args[1]); 4634 4635 if (!isinf(x)) { 4636 if (y == 0.5) { 4637 // It's not uncommon to use Math.pow(x, 0.5) to compute the 4638 // square root of a number. To speed up such computations, we 4639 // explictly check for this case and use the sqrt() function 4640 // which is faster than pow(). 4641 return Heap::AllocateHeapNumber(sqrt(x)); 4642 } else if (y == -0.5) { 4643 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5). 4644 return Heap::AllocateHeapNumber(1.0 / sqrt(x)); 4645 } 4646 } 4647 4648 if (y == 0) { 4649 return Smi::FromInt(1); 4650 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { 4651 return Heap::nan_value(); 4652 } else { 4653 return Heap::AllocateHeapNumber(pow(x, y)); 4654 } 4655} 4656 4657 4658static Object* Runtime_Math_round(Arguments args) { 4659 NoHandleAllocation ha; 4660 ASSERT(args.length() == 1); 4661 4662 CONVERT_DOUBLE_CHECKED(x, args[0]); 4663 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value(); 4664 return Heap::NumberFromDouble(floor(x + 0.5)); 4665} 4666 4667 4668static Object* Runtime_Math_sin(Arguments args) { 4669 NoHandleAllocation ha; 4670 ASSERT(args.length() == 1); 4671 4672 CONVERT_DOUBLE_CHECKED(x, args[0]); 4673 return TranscendentalCache::Get(TranscendentalCache::SIN, x); 4674} 4675 4676 4677static Object* Runtime_Math_sqrt(Arguments args) { 4678 NoHandleAllocation ha; 4679 ASSERT(args.length() == 1); 4680 4681 CONVERT_DOUBLE_CHECKED(x, args[0]); 4682 return Heap::AllocateHeapNumber(sqrt(x)); 4683} 4684 4685 4686static Object* Runtime_Math_tan(Arguments args) { 4687 NoHandleAllocation ha; 4688 ASSERT(args.length() == 1); 4689 4690 CONVERT_DOUBLE_CHECKED(x, args[0]); 4691 return TranscendentalCache::Get(TranscendentalCache::TAN, x); 4692} 4693 4694 4695// The NewArguments function is only used when constructing the 4696// arguments array when calling non-functions from JavaScript in 4697// runtime.js:CALL_NON_FUNCTION. 4698static Object* Runtime_NewArguments(Arguments args) { 4699 NoHandleAllocation ha; 4700 ASSERT(args.length() == 1); 4701 4702 // ECMA-262, 3rd., 10.1.8, p.39 4703 CONVERT_CHECKED(JSFunction, callee, args[0]); 4704 4705 // Compute the frame holding the arguments. 4706 JavaScriptFrameIterator it; 4707 it.AdvanceToArgumentsFrame(); 4708 JavaScriptFrame* frame = it.frame(); 4709 4710 const int length = frame->GetProvidedParametersCount(); 4711 Object* result = Heap::AllocateArgumentsObject(callee, length); 4712 if (result->IsFailure()) return result; 4713 if (length > 0) { 4714 Object* obj = Heap::AllocateFixedArray(length); 4715 if (obj->IsFailure()) return obj; 4716 FixedArray* array = FixedArray::cast(obj); 4717 ASSERT(array->length() == length); 4718 WriteBarrierMode mode = array->GetWriteBarrierMode(); 4719 for (int i = 0; i < length; i++) { 4720 array->set(i, frame->GetParameter(i), mode); 4721 } 4722 JSObject::cast(result)->set_elements(array); 4723 } 4724 return result; 4725} 4726 4727 4728static Object* Runtime_NewArgumentsFast(Arguments args) { 4729 NoHandleAllocation ha; 4730 ASSERT(args.length() == 3); 4731 4732 JSFunction* callee = JSFunction::cast(args[0]); 4733 Object** parameters = reinterpret_cast<Object**>(args[1]); 4734 const int length = Smi::cast(args[2])->value(); 4735 4736 Object* result = Heap::AllocateArgumentsObject(callee, length); 4737 if (result->IsFailure()) return result; 4738 // Allocate the elements if needed. 4739 if (length > 0) { 4740 // Allocate the fixed array. 4741 Object* obj = Heap::AllocateRawFixedArray(length); 4742 if (obj->IsFailure()) return obj; 4743 reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map()); 4744 FixedArray* array = FixedArray::cast(obj); 4745 array->set_length(length); 4746 WriteBarrierMode mode = array->GetWriteBarrierMode(); 4747 for (int i = 0; i < length; i++) { 4748 array->set(i, *--parameters, mode); 4749 } 4750 JSObject::cast(result)->set_elements(FixedArray::cast(obj)); 4751 } 4752 return result; 4753} 4754 4755 4756static Object* Runtime_NewClosure(Arguments args) { 4757 HandleScope scope; 4758 ASSERT(args.length() == 2); 4759 CONVERT_ARG_CHECKED(Context, context, 0); 4760 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 1); 4761 4762 PretenureFlag pretenure = (context->global_context() == *context) 4763 ? TENURED // Allocate global closures in old space. 4764 : NOT_TENURED; // Allocate local closures in new space. 4765 Handle<JSFunction> result = 4766 Factory::NewFunctionFromBoilerplate(boilerplate, context, pretenure); 4767 return *result; 4768} 4769 4770 4771static Code* ComputeConstructStub(Handle<SharedFunctionInfo> shared) { 4772 // TODO(385): Change this to create a construct stub specialized for 4773 // the given map to make allocation of simple objects - and maybe 4774 // arrays - much faster. 4775 if (FLAG_inline_new 4776 && shared->has_only_simple_this_property_assignments()) { 4777 ConstructStubCompiler compiler; 4778 Object* code = compiler.CompileConstructStub(*shared); 4779 if (code->IsFailure()) { 4780 return Builtins::builtin(Builtins::JSConstructStubGeneric); 4781 } 4782 return Code::cast(code); 4783 } 4784 4785 return shared->construct_stub(); 4786} 4787 4788 4789static Object* Runtime_NewObject(Arguments args) { 4790 HandleScope scope; 4791 ASSERT(args.length() == 1); 4792 4793 Handle<Object> constructor = args.at<Object>(0); 4794 4795 // If the constructor isn't a proper function we throw a type error. 4796 if (!constructor->IsJSFunction()) { 4797 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 4798 Handle<Object> type_error = 4799 Factory::NewTypeError("not_constructor", arguments); 4800 return Top::Throw(*type_error); 4801 } 4802 4803 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor); 4804#ifdef ENABLE_DEBUGGER_SUPPORT 4805 // Handle stepping into constructors if step into is active. 4806 if (Debug::StepInActive()) { 4807 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true); 4808 } 4809#endif 4810 4811 if (function->has_initial_map()) { 4812 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { 4813 // The 'Function' function ignores the receiver object when 4814 // called using 'new' and creates a new JSFunction object that 4815 // is returned. The receiver object is only used for error 4816 // reporting if an error occurs when constructing the new 4817 // JSFunction. Factory::NewJSObject() should not be used to 4818 // allocate JSFunctions since it does not properly initialize 4819 // the shared part of the function. Since the receiver is 4820 // ignored anyway, we use the global object as the receiver 4821 // instead of a new JSFunction object. This way, errors are 4822 // reported the same way whether or not 'Function' is called 4823 // using 'new'. 4824 return Top::context()->global(); 4825 } 4826 } 4827 4828 // The function should be compiled for the optimization hints to be available. 4829 if (!function->shared()->is_compiled()) { 4830 CompileLazyShared(Handle<SharedFunctionInfo>(function->shared()), 4831 CLEAR_EXCEPTION, 4832 0); 4833 LOG(FunctionCreateEvent(*function)); 4834 } 4835 4836 bool first_allocation = !function->has_initial_map(); 4837 Handle<JSObject> result = Factory::NewJSObject(function); 4838 if (first_allocation) { 4839 Handle<Map> map = Handle<Map>(function->initial_map()); 4840 Handle<Code> stub = Handle<Code>( 4841 ComputeConstructStub(Handle<SharedFunctionInfo>(function->shared()))); 4842 function->shared()->set_construct_stub(*stub); 4843 } 4844 4845 Counters::constructed_objects.Increment(); 4846 Counters::constructed_objects_runtime.Increment(); 4847 4848 return *result; 4849} 4850 4851 4852static Object* Runtime_LazyCompile(Arguments args) { 4853 HandleScope scope; 4854 ASSERT(args.length() == 1); 4855 4856 Handle<JSFunction> function = args.at<JSFunction>(0); 4857#ifdef DEBUG 4858 if (FLAG_trace_lazy) { 4859 PrintF("[lazy: "); 4860 function->shared()->name()->Print(); 4861 PrintF("]\n"); 4862 } 4863#endif 4864 4865 // Compile the target function. Here we compile using CompileLazyInLoop in 4866 // order to get the optimized version. This helps code like delta-blue 4867 // that calls performance-critical routines through constructors. A 4868 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a 4869 // direct call. Since the in-loop tracking takes place through CallICs 4870 // this means that things called through constructors are never known to 4871 // be in loops. We compile them as if they are in loops here just in case. 4872 ASSERT(!function->is_compiled()); 4873 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) { 4874 return Failure::Exception(); 4875 } 4876 4877 return function->code(); 4878} 4879 4880 4881static Object* Runtime_GetCalledFunction(Arguments args) { 4882 HandleScope scope; 4883 ASSERT(args.length() == 0); 4884 StackFrameIterator it; 4885 // Get past the JS-to-C exit frame. 4886 ASSERT(it.frame()->is_exit()); 4887 it.Advance(); 4888 // Get past the CALL_NON_FUNCTION activation frame. 4889 ASSERT(it.frame()->is_java_script()); 4890 it.Advance(); 4891 // Argument adaptor frames do not copy the function; we have to skip 4892 // past them to get to the real calling frame. 4893 if (it.frame()->is_arguments_adaptor()) it.Advance(); 4894 // Get the function from the top of the expression stack of the 4895 // calling frame. 4896 StandardFrame* frame = StandardFrame::cast(it.frame()); 4897 int index = frame->ComputeExpressionsCount() - 1; 4898 Object* result = frame->GetExpression(index); 4899 return result; 4900} 4901 4902 4903static Object* Runtime_GetFunctionDelegate(Arguments args) { 4904 HandleScope scope; 4905 ASSERT(args.length() == 1); 4906 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 4907 return *Execution::GetFunctionDelegate(args.at<Object>(0)); 4908} 4909 4910 4911static Object* Runtime_GetConstructorDelegate(Arguments args) { 4912 HandleScope scope; 4913 ASSERT(args.length() == 1); 4914 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 4915 return *Execution::GetConstructorDelegate(args.at<Object>(0)); 4916} 4917 4918 4919static Object* Runtime_NewContext(Arguments args) { 4920 NoHandleAllocation ha; 4921 ASSERT(args.length() == 1); 4922 4923 CONVERT_CHECKED(JSFunction, function, args[0]); 4924 int length = ScopeInfo<>::NumberOfContextSlots(function->code()); 4925 Object* result = Heap::AllocateFunctionContext(length, function); 4926 if (result->IsFailure()) return result; 4927 4928 Top::set_context(Context::cast(result)); 4929 4930 return result; // non-failure 4931} 4932 4933static Object* PushContextHelper(Object* object, bool is_catch_context) { 4934 // Convert the object to a proper JavaScript object. 4935 Object* js_object = object; 4936 if (!js_object->IsJSObject()) { 4937 js_object = js_object->ToObject(); 4938 if (js_object->IsFailure()) { 4939 if (!Failure::cast(js_object)->IsInternalError()) return js_object; 4940 HandleScope scope; 4941 Handle<Object> handle(object); 4942 Handle<Object> result = 4943 Factory::NewTypeError("with_expression", HandleVector(&handle, 1)); 4944 return Top::Throw(*result); 4945 } 4946 } 4947 4948 Object* result = 4949 Heap::AllocateWithContext(Top::context(), 4950 JSObject::cast(js_object), 4951 is_catch_context); 4952 if (result->IsFailure()) return result; 4953 4954 Context* context = Context::cast(result); 4955 Top::set_context(context); 4956 4957 return result; 4958} 4959 4960 4961static Object* Runtime_PushContext(Arguments args) { 4962 NoHandleAllocation ha; 4963 ASSERT(args.length() == 1); 4964 return PushContextHelper(args[0], false); 4965} 4966 4967 4968static Object* Runtime_PushCatchContext(Arguments args) { 4969 NoHandleAllocation ha; 4970 ASSERT(args.length() == 1); 4971 return PushContextHelper(args[0], true); 4972} 4973 4974 4975static Object* Runtime_LookupContext(Arguments args) { 4976 HandleScope scope; 4977 ASSERT(args.length() == 2); 4978 4979 CONVERT_ARG_CHECKED(Context, context, 0); 4980 CONVERT_ARG_CHECKED(String, name, 1); 4981 4982 int index; 4983 PropertyAttributes attributes; 4984 ContextLookupFlags flags = FOLLOW_CHAINS; 4985 Handle<Object> holder = 4986 context->Lookup(name, flags, &index, &attributes); 4987 4988 if (index < 0 && !holder.is_null()) { 4989 ASSERT(holder->IsJSObject()); 4990 return *holder; 4991 } 4992 4993 // No intermediate context found. Use global object by default. 4994 return Top::context()->global(); 4995} 4996 4997 4998// A mechanism to return a pair of Object pointers in registers (if possible). 4999// How this is achieved is calling convention-dependent. 5000// All currently supported x86 compiles uses calling conventions that are cdecl 5001// variants where a 64-bit value is returned in two 32-bit registers 5002// (edx:eax on ia32, r1:r0 on ARM). 5003// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. 5004// In Win64 calling convention, a struct of two pointers is returned in memory, 5005// allocated by the caller, and passed as a pointer in a hidden first parameter. 5006#ifdef V8_HOST_ARCH_64_BIT 5007struct ObjectPair { 5008 Object* x; 5009 Object* y; 5010}; 5011 5012static inline ObjectPair MakePair(Object* x, Object* y) { 5013 ObjectPair result = {x, y}; 5014 // Pointers x and y returned in rax and rdx, in AMD-x64-abi. 5015 // In Win64 they are assigned to a hidden first argument. 5016 return result; 5017} 5018#else 5019typedef uint64_t ObjectPair; 5020static inline ObjectPair MakePair(Object* x, Object* y) { 5021 return reinterpret_cast<uint32_t>(x) | 5022 (reinterpret_cast<ObjectPair>(y) << 32); 5023} 5024#endif 5025 5026 5027static inline Object* Unhole(Object* x, PropertyAttributes attributes) { 5028 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); 5029 USE(attributes); 5030 return x->IsTheHole() ? Heap::undefined_value() : x; 5031} 5032 5033 5034static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) { 5035 ASSERT(!holder->IsGlobalObject()); 5036 Context* top = Top::context(); 5037 // Get the context extension function. 5038 JSFunction* context_extension_function = 5039 top->global_context()->context_extension_function(); 5040 // If the holder isn't a context extension object, we just return it 5041 // as the receiver. This allows arguments objects to be used as 5042 // receivers, but only if they are put in the context scope chain 5043 // explicitly via a with-statement. 5044 Object* constructor = holder->map()->constructor(); 5045 if (constructor != context_extension_function) return holder; 5046 // Fall back to using the global object as the receiver if the 5047 // property turns out to be a local variable allocated in a context 5048 // extension object - introduced via eval. 5049 return top->global()->global_receiver(); 5050} 5051 5052 5053static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) { 5054 HandleScope scope; 5055 ASSERT_EQ(2, args.length()); 5056 5057 if (!args[0]->IsContext() || !args[1]->IsString()) { 5058 return MakePair(Top::ThrowIllegalOperation(), NULL); 5059 } 5060 Handle<Context> context = args.at<Context>(0); 5061 Handle<String> name = args.at<String>(1); 5062 5063 int index; 5064 PropertyAttributes attributes; 5065 ContextLookupFlags flags = FOLLOW_CHAINS; 5066 Handle<Object> holder = 5067 context->Lookup(name, flags, &index, &attributes); 5068 5069 // If the index is non-negative, the slot has been found in a local 5070 // variable or a parameter. Read it from the context object or the 5071 // arguments object. 5072 if (index >= 0) { 5073 // If the "property" we were looking for is a local variable or an 5074 // argument in a context, the receiver is the global object; see 5075 // ECMA-262, 3rd., 10.1.6 and 10.2.3. 5076 JSObject* receiver = Top::context()->global()->global_receiver(); 5077 Object* value = (holder->IsContext()) 5078 ? Context::cast(*holder)->get(index) 5079 : JSObject::cast(*holder)->GetElement(index); 5080 return MakePair(Unhole(value, attributes), receiver); 5081 } 5082 5083 // If the holder is found, we read the property from it. 5084 if (!holder.is_null() && holder->IsJSObject()) { 5085 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name)); 5086 JSObject* object = JSObject::cast(*holder); 5087 JSObject* receiver; 5088 if (object->IsGlobalObject()) { 5089 receiver = GlobalObject::cast(object)->global_receiver(); 5090 } else if (context->is_exception_holder(*holder)) { 5091 receiver = Top::context()->global()->global_receiver(); 5092 } else { 5093 receiver = ComputeReceiverForNonGlobal(object); 5094 } 5095 // No need to unhole the value here. This is taken care of by the 5096 // GetProperty function. 5097 Object* value = object->GetProperty(*name); 5098 return MakePair(value, receiver); 5099 } 5100 5101 if (throw_error) { 5102 // The property doesn't exist - throw exception. 5103 Handle<Object> reference_error = 5104 Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); 5105 return MakePair(Top::Throw(*reference_error), NULL); 5106 } else { 5107 // The property doesn't exist - return undefined 5108 return MakePair(Heap::undefined_value(), Heap::undefined_value()); 5109 } 5110} 5111 5112 5113static ObjectPair Runtime_LoadContextSlot(Arguments args) { 5114 return LoadContextSlotHelper(args, true); 5115} 5116 5117 5118static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) { 5119 return LoadContextSlotHelper(args, false); 5120} 5121 5122 5123static Object* Runtime_StoreContextSlot(Arguments args) { 5124 HandleScope scope; 5125 ASSERT(args.length() == 3); 5126 5127 Handle<Object> value(args[0]); 5128 CONVERT_ARG_CHECKED(Context, context, 1); 5129 CONVERT_ARG_CHECKED(String, name, 2); 5130 5131 int index; 5132 PropertyAttributes attributes; 5133 ContextLookupFlags flags = FOLLOW_CHAINS; 5134 Handle<Object> holder = 5135 context->Lookup(name, flags, &index, &attributes); 5136 5137 if (index >= 0) { 5138 if (holder->IsContext()) { 5139 // Ignore if read_only variable. 5140 if ((attributes & READ_ONLY) == 0) { 5141 Handle<Context>::cast(holder)->set(index, *value); 5142 } 5143 } else { 5144 ASSERT((attributes & READ_ONLY) == 0); 5145 Object* result = 5146 Handle<JSObject>::cast(holder)->SetElement(index, *value); 5147 USE(result); 5148 ASSERT(!result->IsFailure()); 5149 } 5150 return *value; 5151 } 5152 5153 // Slow case: The property is not in a FixedArray context. 5154 // It is either in an JSObject extension context or it was not found. 5155 Handle<JSObject> context_ext; 5156 5157 if (!holder.is_null()) { 5158 // The property exists in the extension context. 5159 context_ext = Handle<JSObject>::cast(holder); 5160 } else { 5161 // The property was not found. It needs to be stored in the global context. 5162 ASSERT(attributes == ABSENT); 5163 attributes = NONE; 5164 context_ext = Handle<JSObject>(Top::context()->global()); 5165 } 5166 5167 // Set the property, but ignore if read_only variable on the context 5168 // extension object itself. 5169 if ((attributes & READ_ONLY) == 0 || 5170 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { 5171 Handle<Object> set = SetProperty(context_ext, name, value, attributes); 5172 if (set.is_null()) { 5173 // Failure::Exception is converted to a null handle in the 5174 // handle-based methods such as SetProperty. We therefore need 5175 // to convert null handles back to exceptions. 5176 ASSERT(Top::has_pending_exception()); 5177 return Failure::Exception(); 5178 } 5179 } 5180 return *value; 5181} 5182 5183 5184static Object* Runtime_Throw(Arguments args) { 5185 HandleScope scope; 5186 ASSERT(args.length() == 1); 5187 5188 return Top::Throw(args[0]); 5189} 5190 5191 5192static Object* Runtime_ReThrow(Arguments args) { 5193 HandleScope scope; 5194 ASSERT(args.length() == 1); 5195 5196 return Top::ReThrow(args[0]); 5197} 5198 5199 5200static Object* Runtime_PromoteScheduledException(Arguments args) { 5201 ASSERT_EQ(0, args.length()); 5202 return Top::PromoteScheduledException(); 5203} 5204 5205 5206static Object* Runtime_ThrowReferenceError(Arguments args) { 5207 HandleScope scope; 5208 ASSERT(args.length() == 1); 5209 5210 Handle<Object> name(args[0]); 5211 Handle<Object> reference_error = 5212 Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); 5213 return Top::Throw(*reference_error); 5214} 5215 5216 5217static Object* Runtime_StackOverflow(Arguments args) { 5218 NoHandleAllocation na; 5219 return Top::StackOverflow(); 5220} 5221 5222 5223static Object* Runtime_StackGuard(Arguments args) { 5224 ASSERT(args.length() == 1); 5225 5226 // First check if this is a real stack overflow. 5227 if (StackGuard::IsStackOverflow()) { 5228 return Runtime_StackOverflow(args); 5229 } 5230 5231 return Execution::HandleStackGuardInterrupt(); 5232} 5233 5234 5235// NOTE: These PrintXXX functions are defined for all builds (not just 5236// DEBUG builds) because we may want to be able to trace function 5237// calls in all modes. 5238static void PrintString(String* str) { 5239 // not uncommon to have empty strings 5240 if (str->length() > 0) { 5241 SmartPointer<char> s = 5242 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 5243 PrintF("%s", *s); 5244 } 5245} 5246 5247 5248static void PrintObject(Object* obj) { 5249 if (obj->IsSmi()) { 5250 PrintF("%d", Smi::cast(obj)->value()); 5251 } else if (obj->IsString() || obj->IsSymbol()) { 5252 PrintString(String::cast(obj)); 5253 } else if (obj->IsNumber()) { 5254 PrintF("%g", obj->Number()); 5255 } else if (obj->IsFailure()) { 5256 PrintF("<failure>"); 5257 } else if (obj->IsUndefined()) { 5258 PrintF("<undefined>"); 5259 } else if (obj->IsNull()) { 5260 PrintF("<null>"); 5261 } else if (obj->IsTrue()) { 5262 PrintF("<true>"); 5263 } else if (obj->IsFalse()) { 5264 PrintF("<false>"); 5265 } else { 5266 PrintF("%p", obj); 5267 } 5268} 5269 5270 5271static int StackSize() { 5272 int n = 0; 5273 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++; 5274 return n; 5275} 5276 5277 5278static void PrintTransition(Object* result) { 5279 // indentation 5280 { const int nmax = 80; 5281 int n = StackSize(); 5282 if (n <= nmax) 5283 PrintF("%4d:%*s", n, n, ""); 5284 else 5285 PrintF("%4d:%*s", n, nmax, "..."); 5286 } 5287 5288 if (result == NULL) { 5289 // constructor calls 5290 JavaScriptFrameIterator it; 5291 JavaScriptFrame* frame = it.frame(); 5292 if (frame->IsConstructor()) PrintF("new "); 5293 // function name 5294 Object* fun = frame->function(); 5295 if (fun->IsJSFunction()) { 5296 PrintObject(JSFunction::cast(fun)->shared()->name()); 5297 } else { 5298 PrintObject(fun); 5299 } 5300 // function arguments 5301 // (we are intentionally only printing the actually 5302 // supplied parameters, not all parameters required) 5303 PrintF("(this="); 5304 PrintObject(frame->receiver()); 5305 const int length = frame->GetProvidedParametersCount(); 5306 for (int i = 0; i < length; i++) { 5307 PrintF(", "); 5308 PrintObject(frame->GetParameter(i)); 5309 } 5310 PrintF(") {\n"); 5311 5312 } else { 5313 // function result 5314 PrintF("} -> "); 5315 PrintObject(result); 5316 PrintF("\n"); 5317 } 5318} 5319 5320 5321static Object* Runtime_TraceEnter(Arguments args) { 5322 ASSERT(args.length() == 0); 5323 NoHandleAllocation ha; 5324 PrintTransition(NULL); 5325 return Heap::undefined_value(); 5326} 5327 5328 5329static Object* Runtime_TraceExit(Arguments args) { 5330 NoHandleAllocation ha; 5331 PrintTransition(args[0]); 5332 return args[0]; // return TOS 5333} 5334 5335 5336static Object* Runtime_DebugPrint(Arguments args) { 5337 NoHandleAllocation ha; 5338 ASSERT(args.length() == 1); 5339 5340#ifdef DEBUG 5341 if (args[0]->IsString()) { 5342 // If we have a string, assume it's a code "marker" 5343 // and print some interesting cpu debugging info. 5344 JavaScriptFrameIterator it; 5345 JavaScriptFrame* frame = it.frame(); 5346 PrintF("fp = %p, sp = %p, caller_sp = %p: ", 5347 frame->fp(), frame->sp(), frame->caller_sp()); 5348 } else { 5349 PrintF("DebugPrint: "); 5350 } 5351 args[0]->Print(); 5352 if (args[0]->IsHeapObject()) { 5353 HeapObject::cast(args[0])->map()->Print(); 5354 } 5355#else 5356 // ShortPrint is available in release mode. Print is not. 5357 args[0]->ShortPrint(); 5358#endif 5359 PrintF("\n"); 5360 Flush(); 5361 5362 return args[0]; // return TOS 5363} 5364 5365 5366static Object* Runtime_DebugTrace(Arguments args) { 5367 ASSERT(args.length() == 0); 5368 NoHandleAllocation ha; 5369 Top::PrintStack(); 5370 return Heap::undefined_value(); 5371} 5372 5373 5374static Object* Runtime_DateCurrentTime(Arguments args) { 5375 NoHandleAllocation ha; 5376 ASSERT(args.length() == 0); 5377 5378 // According to ECMA-262, section 15.9.1, page 117, the precision of 5379 // the number in a Date object representing a particular instant in 5380 // time is milliseconds. Therefore, we floor the result of getting 5381 // the OS time. 5382 double millis = floor(OS::TimeCurrentMillis()); 5383 return Heap::NumberFromDouble(millis); 5384} 5385 5386 5387static Object* Runtime_DateParseString(Arguments args) { 5388 HandleScope scope; 5389 ASSERT(args.length() == 2); 5390 5391 CONVERT_ARG_CHECKED(String, str, 0); 5392 FlattenString(str); 5393 5394 CONVERT_ARG_CHECKED(JSArray, output, 1); 5395 RUNTIME_ASSERT(output->HasFastElements()); 5396 5397 AssertNoAllocation no_allocation; 5398 5399 FixedArray* output_array = FixedArray::cast(output->elements()); 5400 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); 5401 bool result; 5402 if (str->IsAsciiRepresentation()) { 5403 result = DateParser::Parse(str->ToAsciiVector(), output_array); 5404 } else { 5405 ASSERT(str->IsTwoByteRepresentation()); 5406 result = DateParser::Parse(str->ToUC16Vector(), output_array); 5407 } 5408 5409 if (result) { 5410 return *output; 5411 } else { 5412 return Heap::null_value(); 5413 } 5414} 5415 5416 5417static Object* Runtime_DateLocalTimezone(Arguments args) { 5418 NoHandleAllocation ha; 5419 ASSERT(args.length() == 1); 5420 5421 CONVERT_DOUBLE_CHECKED(x, args[0]); 5422 const char* zone = OS::LocalTimezone(x); 5423 return Heap::AllocateStringFromUtf8(CStrVector(zone)); 5424} 5425 5426 5427static Object* Runtime_DateLocalTimeOffset(Arguments args) { 5428 NoHandleAllocation ha; 5429 ASSERT(args.length() == 0); 5430 5431 return Heap::NumberFromDouble(OS::LocalTimeOffset()); 5432} 5433 5434 5435static Object* Runtime_DateDaylightSavingsOffset(Arguments args) { 5436 NoHandleAllocation ha; 5437 ASSERT(args.length() == 1); 5438 5439 CONVERT_DOUBLE_CHECKED(x, args[0]); 5440 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x)); 5441} 5442 5443 5444static Object* Runtime_NumberIsFinite(Arguments args) { 5445 NoHandleAllocation ha; 5446 ASSERT(args.length() == 1); 5447 5448 CONVERT_DOUBLE_CHECKED(value, args[0]); 5449 Object* result; 5450 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) { 5451 result = Heap::false_value(); 5452 } else { 5453 result = Heap::true_value(); 5454 } 5455 return result; 5456} 5457 5458 5459static Object* Runtime_GlobalReceiver(Arguments args) { 5460 ASSERT(args.length() == 1); 5461 Object* global = args[0]; 5462 if (!global->IsJSGlobalObject()) return Heap::null_value(); 5463 return JSGlobalObject::cast(global)->global_receiver(); 5464} 5465 5466 5467static Object* Runtime_CompileString(Arguments args) { 5468 HandleScope scope; 5469 ASSERT_EQ(2, args.length()); 5470 CONVERT_ARG_CHECKED(String, source, 0); 5471 CONVERT_ARG_CHECKED(Oddball, is_json, 1) 5472 5473 // Compile source string in the global context. 5474 Handle<Context> context(Top::context()->global_context()); 5475 Compiler::ValidationState validate = (is_json->IsTrue()) 5476 ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON; 5477 Handle<JSFunction> boilerplate = Compiler::CompileEval(source, 5478 context, 5479 true, 5480 validate); 5481 if (boilerplate.is_null()) return Failure::Exception(); 5482 Handle<JSFunction> fun = 5483 Factory::NewFunctionFromBoilerplate(boilerplate, context, NOT_TENURED); 5484 return *fun; 5485} 5486 5487 5488static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) { 5489 ASSERT(args.length() == 3); 5490 if (!args[0]->IsJSFunction()) { 5491 return MakePair(Top::ThrowIllegalOperation(), NULL); 5492 } 5493 5494 HandleScope scope; 5495 Handle<JSFunction> callee = args.at<JSFunction>(0); 5496 Handle<Object> receiver; // Will be overwritten. 5497 5498 // Compute the calling context. 5499 Handle<Context> context = Handle<Context>(Top::context()); 5500#ifdef DEBUG 5501 // Make sure Top::context() agrees with the old code that traversed 5502 // the stack frames to compute the context. 5503 StackFrameLocator locator; 5504 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 5505 ASSERT(Context::cast(frame->context()) == *context); 5506#endif 5507 5508 // Find where the 'eval' symbol is bound. It is unaliased only if 5509 // it is bound in the global context. 5510 int index = -1; 5511 PropertyAttributes attributes = ABSENT; 5512 while (true) { 5513 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN, 5514 &index, &attributes); 5515 // Stop search when eval is found or when the global context is 5516 // reached. 5517 if (attributes != ABSENT || context->IsGlobalContext()) break; 5518 if (context->is_function_context()) { 5519 context = Handle<Context>(Context::cast(context->closure()->context())); 5520 } else { 5521 context = Handle<Context>(context->previous()); 5522 } 5523 } 5524 5525 // If eval could not be resolved, it has been deleted and we need to 5526 // throw a reference error. 5527 if (attributes == ABSENT) { 5528 Handle<Object> name = Factory::eval_symbol(); 5529 Handle<Object> reference_error = 5530 Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); 5531 return MakePair(Top::Throw(*reference_error), NULL); 5532 } 5533 5534 if (!context->IsGlobalContext()) { 5535 // 'eval' is not bound in the global context. Just call the function 5536 // with the given arguments. This is not necessarily the global eval. 5537 if (receiver->IsContext()) { 5538 context = Handle<Context>::cast(receiver); 5539 receiver = Handle<Object>(context->get(index)); 5540 } else if (receiver->IsJSContextExtensionObject()) { 5541 receiver = Handle<JSObject>(Top::context()->global()->global_receiver()); 5542 } 5543 return MakePair(*callee, *receiver); 5544 } 5545 5546 // 'eval' is bound in the global context, but it may have been overwritten. 5547 // Compare it to the builtin 'GlobalEval' function to make sure. 5548 if (*callee != Top::global_context()->global_eval_fun() || 5549 !args[1]->IsString()) { 5550 return MakePair(*callee, Top::context()->global()->global_receiver()); 5551 } 5552 5553 // Deal with a normal eval call with a string argument. Compile it 5554 // and return the compiled function bound in the local context. 5555 Handle<String> source = args.at<String>(1); 5556 Handle<JSFunction> boilerplate = Compiler::CompileEval( 5557 source, 5558 Handle<Context>(Top::context()), 5559 Top::context()->IsGlobalContext(), 5560 Compiler::DONT_VALIDATE_JSON); 5561 if (boilerplate.is_null()) return MakePair(Failure::Exception(), NULL); 5562 callee = Factory::NewFunctionFromBoilerplate( 5563 boilerplate, 5564 Handle<Context>(Top::context()), 5565 NOT_TENURED); 5566 return MakePair(*callee, args[2]); 5567} 5568 5569 5570static Object* Runtime_SetNewFunctionAttributes(Arguments args) { 5571 // This utility adjusts the property attributes for newly created Function 5572 // object ("new Function(...)") by changing the map. 5573 // All it does is changing the prototype property to enumerable 5574 // as specified in ECMA262, 15.3.5.2. 5575 HandleScope scope; 5576 ASSERT(args.length() == 1); 5577 CONVERT_ARG_CHECKED(JSFunction, func, 0); 5578 ASSERT(func->map()->instance_type() == 5579 Top::function_instance_map()->instance_type()); 5580 ASSERT(func->map()->instance_size() == 5581 Top::function_instance_map()->instance_size()); 5582 func->set_map(*Top::function_instance_map()); 5583 return *func; 5584} 5585 5586 5587// Push an array unto an array of arrays if it is not already in the 5588// array. Returns true if the element was pushed on the stack and 5589// false otherwise. 5590static Object* Runtime_PushIfAbsent(Arguments args) { 5591 ASSERT(args.length() == 2); 5592 CONVERT_CHECKED(JSArray, array, args[0]); 5593 CONVERT_CHECKED(JSArray, element, args[1]); 5594 RUNTIME_ASSERT(array->HasFastElements()); 5595 int length = Smi::cast(array->length())->value(); 5596 FixedArray* elements = FixedArray::cast(array->elements()); 5597 for (int i = 0; i < length; i++) { 5598 if (elements->get(i) == element) return Heap::false_value(); 5599 } 5600 Object* obj = array->SetFastElement(length, element); 5601 if (obj->IsFailure()) return obj; 5602 return Heap::true_value(); 5603} 5604 5605 5606/** 5607 * A simple visitor visits every element of Array's. 5608 * The backend storage can be a fixed array for fast elements case, 5609 * or a dictionary for sparse array. Since Dictionary is a subtype 5610 * of FixedArray, the class can be used by both fast and slow cases. 5611 * The second parameter of the constructor, fast_elements, specifies 5612 * whether the storage is a FixedArray or Dictionary. 5613 * 5614 * An index limit is used to deal with the situation that a result array 5615 * length overflows 32-bit non-negative integer. 5616 */ 5617class ArrayConcatVisitor { 5618 public: 5619 ArrayConcatVisitor(Handle<FixedArray> storage, 5620 uint32_t index_limit, 5621 bool fast_elements) : 5622 storage_(storage), index_limit_(index_limit), 5623 index_offset_(0), fast_elements_(fast_elements) { } 5624 5625 void visit(uint32_t i, Handle<Object> elm) { 5626 if (i >= index_limit_ - index_offset_) return; 5627 uint32_t index = index_offset_ + i; 5628 5629 if (fast_elements_) { 5630 ASSERT(index < static_cast<uint32_t>(storage_->length())); 5631 storage_->set(index, *elm); 5632 5633 } else { 5634 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_); 5635 Handle<NumberDictionary> result = 5636 Factory::DictionaryAtNumberPut(dict, index, elm); 5637 if (!result.is_identical_to(dict)) 5638 storage_ = result; 5639 } 5640 } 5641 5642 void increase_index_offset(uint32_t delta) { 5643 if (index_limit_ - index_offset_ < delta) { 5644 index_offset_ = index_limit_; 5645 } else { 5646 index_offset_ += delta; 5647 } 5648 } 5649 5650 Handle<FixedArray> storage() { return storage_; } 5651 5652 private: 5653 Handle<FixedArray> storage_; 5654 // Limit on the accepted indices. Elements with indices larger than the 5655 // limit are ignored by the visitor. 5656 uint32_t index_limit_; 5657 // Index after last seen index. Always less than or equal to index_limit_. 5658 uint32_t index_offset_; 5659 bool fast_elements_; 5660}; 5661 5662 5663template<class ExternalArrayClass, class ElementType> 5664static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver, 5665 bool elements_are_ints, 5666 bool elements_are_guaranteed_smis, 5667 uint32_t range, 5668 ArrayConcatVisitor* visitor) { 5669 Handle<ExternalArrayClass> array( 5670 ExternalArrayClass::cast(receiver->elements())); 5671 uint32_t len = Min(static_cast<uint32_t>(array->length()), range); 5672 5673 if (visitor != NULL) { 5674 if (elements_are_ints) { 5675 if (elements_are_guaranteed_smis) { 5676 for (uint32_t j = 0; j < len; j++) { 5677 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j)))); 5678 visitor->visit(j, e); 5679 } 5680 } else { 5681 for (uint32_t j = 0; j < len; j++) { 5682 int64_t val = static_cast<int64_t>(array->get(j)); 5683 if (Smi::IsValid(static_cast<intptr_t>(val))) { 5684 Handle<Smi> e(Smi::FromInt(static_cast<int>(val))); 5685 visitor->visit(j, e); 5686 } else { 5687 Handle<Object> e( 5688 Heap::AllocateHeapNumber(static_cast<ElementType>(val))); 5689 visitor->visit(j, e); 5690 } 5691 } 5692 } 5693 } else { 5694 for (uint32_t j = 0; j < len; j++) { 5695 Handle<Object> e(Heap::AllocateHeapNumber(array->get(j))); 5696 visitor->visit(j, e); 5697 } 5698 } 5699 } 5700 5701 return len; 5702} 5703 5704/** 5705 * A helper function that visits elements of a JSObject. Only elements 5706 * whose index between 0 and range (exclusive) are visited. 5707 * 5708 * If the third parameter, visitor, is not NULL, the visitor is called 5709 * with parameters, 'visitor_index_offset + element index' and the element. 5710 * 5711 * It returns the number of visisted elements. 5712 */ 5713static uint32_t IterateElements(Handle<JSObject> receiver, 5714 uint32_t range, 5715 ArrayConcatVisitor* visitor) { 5716 uint32_t num_of_elements = 0; 5717 5718 switch (receiver->GetElementsKind()) { 5719 case JSObject::FAST_ELEMENTS: { 5720 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 5721 uint32_t len = elements->length(); 5722 if (range < len) { 5723 len = range; 5724 } 5725 5726 for (uint32_t j = 0; j < len; j++) { 5727 Handle<Object> e(elements->get(j)); 5728 if (!e->IsTheHole()) { 5729 num_of_elements++; 5730 if (visitor) { 5731 visitor->visit(j, e); 5732 } 5733 } 5734 } 5735 break; 5736 } 5737 case JSObject::PIXEL_ELEMENTS: { 5738 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements())); 5739 uint32_t len = pixels->length(); 5740 if (range < len) { 5741 len = range; 5742 } 5743 5744 for (uint32_t j = 0; j < len; j++) { 5745 num_of_elements++; 5746 if (visitor != NULL) { 5747 Handle<Smi> e(Smi::FromInt(pixels->get(j))); 5748 visitor->visit(j, e); 5749 } 5750 } 5751 break; 5752 } 5753 case JSObject::EXTERNAL_BYTE_ELEMENTS: { 5754 num_of_elements = 5755 IterateExternalArrayElements<ExternalByteArray, int8_t>( 5756 receiver, true, true, range, visitor); 5757 break; 5758 } 5759 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 5760 num_of_elements = 5761 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( 5762 receiver, true, true, range, visitor); 5763 break; 5764 } 5765 case JSObject::EXTERNAL_SHORT_ELEMENTS: { 5766 num_of_elements = 5767 IterateExternalArrayElements<ExternalShortArray, int16_t>( 5768 receiver, true, true, range, visitor); 5769 break; 5770 } 5771 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 5772 num_of_elements = 5773 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( 5774 receiver, true, true, range, visitor); 5775 break; 5776 } 5777 case JSObject::EXTERNAL_INT_ELEMENTS: { 5778 num_of_elements = 5779 IterateExternalArrayElements<ExternalIntArray, int32_t>( 5780 receiver, true, false, range, visitor); 5781 break; 5782 } 5783 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { 5784 num_of_elements = 5785 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( 5786 receiver, true, false, range, visitor); 5787 break; 5788 } 5789 case JSObject::EXTERNAL_FLOAT_ELEMENTS: { 5790 num_of_elements = 5791 IterateExternalArrayElements<ExternalFloatArray, float>( 5792 receiver, false, false, range, visitor); 5793 break; 5794 } 5795 case JSObject::DICTIONARY_ELEMENTS: { 5796 Handle<NumberDictionary> dict(receiver->element_dictionary()); 5797 uint32_t capacity = dict->Capacity(); 5798 for (uint32_t j = 0; j < capacity; j++) { 5799 Handle<Object> k(dict->KeyAt(j)); 5800 if (dict->IsKey(*k)) { 5801 ASSERT(k->IsNumber()); 5802 uint32_t index = static_cast<uint32_t>(k->Number()); 5803 if (index < range) { 5804 num_of_elements++; 5805 if (visitor) { 5806 visitor->visit(index, Handle<Object>(dict->ValueAt(j))); 5807 } 5808 } 5809 } 5810 } 5811 break; 5812 } 5813 default: 5814 UNREACHABLE(); 5815 break; 5816 } 5817 5818 return num_of_elements; 5819} 5820 5821 5822/** 5823 * A helper function that visits elements of an Array object, and elements 5824 * on its prototypes. 5825 * 5826 * Elements on prototypes are visited first, and only elements whose indices 5827 * less than Array length are visited. 5828 * 5829 * If a ArrayConcatVisitor object is given, the visitor is called with 5830 * parameters, element's index + visitor_index_offset and the element. 5831 * 5832 * The returned number of elements is an upper bound on the actual number 5833 * of elements added. If the same element occurs in more than one object 5834 * in the array's prototype chain, it will be counted more than once, but 5835 * will only occur once in the result. 5836 */ 5837static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array, 5838 ArrayConcatVisitor* visitor) { 5839 uint32_t range = static_cast<uint32_t>(array->length()->Number()); 5840 Handle<Object> obj = array; 5841 5842 static const int kEstimatedPrototypes = 3; 5843 List< Handle<JSObject> > objects(kEstimatedPrototypes); 5844 5845 // Visit prototype first. If an element on the prototype is shadowed by 5846 // the inheritor using the same index, the ArrayConcatVisitor visits 5847 // the prototype element before the shadowing element. 5848 // The visitor can simply overwrite the old value by new value using 5849 // the same index. This follows Array::concat semantics. 5850 while (!obj->IsNull()) { 5851 objects.Add(Handle<JSObject>::cast(obj)); 5852 obj = Handle<Object>(obj->GetPrototype()); 5853 } 5854 5855 uint32_t nof_elements = 0; 5856 for (int i = objects.length() - 1; i >= 0; i--) { 5857 Handle<JSObject> obj = objects[i]; 5858 uint32_t encountered_elements = 5859 IterateElements(Handle<JSObject>::cast(obj), range, visitor); 5860 5861 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) { 5862 nof_elements = JSObject::kMaxElementCount; 5863 } else { 5864 nof_elements += encountered_elements; 5865 } 5866 } 5867 5868 return nof_elements; 5869} 5870 5871 5872/** 5873 * A helper function of Runtime_ArrayConcat. 5874 * 5875 * The first argument is an Array of arrays and objects. It is the 5876 * same as the arguments array of Array::concat JS function. 5877 * 5878 * If an argument is an Array object, the function visits array 5879 * elements. If an argument is not an Array object, the function 5880 * visits the object as if it is an one-element array. 5881 * 5882 * If the result array index overflows 32-bit unsigned integer, the rounded 5883 * non-negative number is used as new length. For example, if one 5884 * array length is 2^32 - 1, second array length is 1, the 5885 * concatenated array length is 0. 5886 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length 5887 * is one more than the last array index to get a value assigned). 5888 */ 5889static uint32_t IterateArguments(Handle<JSArray> arguments, 5890 ArrayConcatVisitor* visitor) { 5891 uint32_t visited_elements = 0; 5892 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 5893 5894 for (uint32_t i = 0; i < num_of_args; i++) { 5895 Handle<Object> obj(arguments->GetElement(i)); 5896 if (obj->IsJSArray()) { 5897 Handle<JSArray> array = Handle<JSArray>::cast(obj); 5898 uint32_t len = static_cast<uint32_t>(array->length()->Number()); 5899 uint32_t nof_elements = 5900 IterateArrayAndPrototypeElements(array, visitor); 5901 // Total elements of array and its prototype chain can be more than 5902 // the array length, but ArrayConcat can only concatenate at most 5903 // the array length number of elements. We use the length as an estimate 5904 // for the actual number of elements added. 5905 uint32_t added_elements = (nof_elements > len) ? len : nof_elements; 5906 if (JSArray::kMaxElementCount - visited_elements < added_elements) { 5907 visited_elements = JSArray::kMaxElementCount; 5908 } else { 5909 visited_elements += added_elements; 5910 } 5911 if (visitor) visitor->increase_index_offset(len); 5912 } else { 5913 if (visitor) { 5914 visitor->visit(0, obj); 5915 visitor->increase_index_offset(1); 5916 } 5917 if (visited_elements < JSArray::kMaxElementCount) { 5918 visited_elements++; 5919 } 5920 } 5921 } 5922 return visited_elements; 5923} 5924 5925 5926/** 5927 * Array::concat implementation. 5928 * See ECMAScript 262, 15.4.4.4. 5929 * TODO(lrn): Fix non-compliance for very large concatenations and update to 5930 * following the ECMAScript 5 specification. 5931 */ 5932static Object* Runtime_ArrayConcat(Arguments args) { 5933 ASSERT(args.length() == 1); 5934 HandleScope handle_scope; 5935 5936 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); 5937 Handle<JSArray> arguments(arg_arrays); 5938 5939 // Pass 1: estimate the number of elements of the result 5940 // (it could be more than real numbers if prototype has elements). 5941 uint32_t result_length = 0; 5942 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 5943 5944 { AssertNoAllocation nogc; 5945 for (uint32_t i = 0; i < num_of_args; i++) { 5946 Object* obj = arguments->GetElement(i); 5947 uint32_t length_estimate; 5948 if (obj->IsJSArray()) { 5949 length_estimate = 5950 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); 5951 } else { 5952 length_estimate = 1; 5953 } 5954 if (JSObject::kMaxElementCount - result_length < length_estimate) { 5955 result_length = JSObject::kMaxElementCount; 5956 break; 5957 } 5958 result_length += length_estimate; 5959 } 5960 } 5961 5962 // Allocate an empty array, will set length and content later. 5963 Handle<JSArray> result = Factory::NewJSArray(0); 5964 5965 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL); 5966 // If estimated number of elements is more than half of length, a 5967 // fixed array (fast case) is more time and space-efficient than a 5968 // dictionary. 5969 bool fast_case = (estimate_nof_elements * 2) >= result_length; 5970 5971 Handle<FixedArray> storage; 5972 if (fast_case) { 5973 // The backing storage array must have non-existing elements to 5974 // preserve holes across concat operations. 5975 storage = Factory::NewFixedArrayWithHoles(result_length); 5976 5977 } else { 5978 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 5979 uint32_t at_least_space_for = estimate_nof_elements + 5980 (estimate_nof_elements >> 2); 5981 storage = Handle<FixedArray>::cast( 5982 Factory::NewNumberDictionary(at_least_space_for)); 5983 } 5984 5985 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length)); 5986 5987 ArrayConcatVisitor visitor(storage, result_length, fast_case); 5988 5989 IterateArguments(arguments, &visitor); 5990 5991 result->set_length(*len); 5992 // Please note the storage might have changed in the visitor. 5993 result->set_elements(*visitor.storage()); 5994 5995 return *result; 5996} 5997 5998 5999// This will not allocate (flatten the string), but it may run 6000// very slowly for very deeply nested ConsStrings. For debugging use only. 6001static Object* Runtime_GlobalPrint(Arguments args) { 6002 NoHandleAllocation ha; 6003 ASSERT(args.length() == 1); 6004 6005 CONVERT_CHECKED(String, string, args[0]); 6006 StringInputBuffer buffer(string); 6007 while (buffer.has_more()) { 6008 uint16_t character = buffer.GetNext(); 6009 PrintF("%c", character); 6010 } 6011 return string; 6012} 6013 6014// Moves all own elements of an object, that are below a limit, to positions 6015// starting at zero. All undefined values are placed after non-undefined values, 6016// and are followed by non-existing element. Does not change the length 6017// property. 6018// Returns the number of non-undefined elements collected. 6019static Object* Runtime_RemoveArrayHoles(Arguments args) { 6020 ASSERT(args.length() == 2); 6021 CONVERT_CHECKED(JSObject, object, args[0]); 6022 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 6023 return object->PrepareElementsForSort(limit); 6024} 6025 6026 6027// Move contents of argument 0 (an array) to argument 1 (an array) 6028static Object* Runtime_MoveArrayContents(Arguments args) { 6029 ASSERT(args.length() == 2); 6030 CONVERT_CHECKED(JSArray, from, args[0]); 6031 CONVERT_CHECKED(JSArray, to, args[1]); 6032 to->SetContent(FixedArray::cast(from->elements())); 6033 to->set_length(from->length()); 6034 from->SetContent(Heap::empty_fixed_array()); 6035 from->set_length(0); 6036 return to; 6037} 6038 6039 6040// How many elements does this array have? 6041static Object* Runtime_EstimateNumberOfElements(Arguments args) { 6042 ASSERT(args.length() == 1); 6043 CONVERT_CHECKED(JSArray, array, args[0]); 6044 HeapObject* elements = array->elements(); 6045 if (elements->IsDictionary()) { 6046 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements()); 6047 } else { 6048 return array->length(); 6049 } 6050} 6051 6052 6053// Returns an array that tells you where in the [0, length) interval an array 6054// might have elements. Can either return keys or intervals. Keys can have 6055// gaps in (undefined). Intervals can also span over some undefined keys. 6056static Object* Runtime_GetArrayKeys(Arguments args) { 6057 ASSERT(args.length() == 2); 6058 HandleScope scope; 6059 CONVERT_ARG_CHECKED(JSObject, array, 0); 6060 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); 6061 if (array->elements()->IsDictionary()) { 6062 // Create an array and get all the keys into it, then remove all the 6063 // keys that are not integers in the range 0 to length-1. 6064 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS); 6065 int keys_length = keys->length(); 6066 for (int i = 0; i < keys_length; i++) { 6067 Object* key = keys->get(i); 6068 uint32_t index; 6069 if (!Array::IndexFromObject(key, &index) || index >= length) { 6070 // Zap invalid keys. 6071 keys->set_undefined(i); 6072 } 6073 } 6074 return *Factory::NewJSArrayWithElements(keys); 6075 } else { 6076 Handle<FixedArray> single_interval = Factory::NewFixedArray(2); 6077 // -1 means start of array. 6078 single_interval->set(0, 6079 Smi::FromInt(-1), 6080 SKIP_WRITE_BARRIER); 6081 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); 6082 uint32_t min_length = actual_length < length ? actual_length : length; 6083 Handle<Object> length_object = 6084 Factory::NewNumber(static_cast<double>(min_length)); 6085 single_interval->set(1, *length_object); 6086 return *Factory::NewJSArrayWithElements(single_interval); 6087 } 6088} 6089 6090 6091// DefineAccessor takes an optional final argument which is the 6092// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due 6093// to the way accessors are implemented, it is set for both the getter 6094// and setter on the first call to DefineAccessor and ignored on 6095// subsequent calls. 6096static Object* Runtime_DefineAccessor(Arguments args) { 6097 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); 6098 // Compute attributes. 6099 PropertyAttributes attributes = NONE; 6100 if (args.length() == 5) { 6101 CONVERT_CHECKED(Smi, attrs, args[4]); 6102 int value = attrs->value(); 6103 // Only attribute bits should be set. 6104 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 6105 attributes = static_cast<PropertyAttributes>(value); 6106 } 6107 6108 CONVERT_CHECKED(JSObject, obj, args[0]); 6109 CONVERT_CHECKED(String, name, args[1]); 6110 CONVERT_CHECKED(Smi, flag, args[2]); 6111 CONVERT_CHECKED(JSFunction, fun, args[3]); 6112 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes); 6113} 6114 6115 6116static Object* Runtime_LookupAccessor(Arguments args) { 6117 ASSERT(args.length() == 3); 6118 CONVERT_CHECKED(JSObject, obj, args[0]); 6119 CONVERT_CHECKED(String, name, args[1]); 6120 CONVERT_CHECKED(Smi, flag, args[2]); 6121 return obj->LookupAccessor(name, flag->value() == 0); 6122} 6123 6124 6125#ifdef ENABLE_DEBUGGER_SUPPORT 6126static Object* Runtime_DebugBreak(Arguments args) { 6127 ASSERT(args.length() == 0); 6128 return Execution::DebugBreakHelper(); 6129} 6130 6131 6132// Helper functions for wrapping and unwrapping stack frame ids. 6133static Smi* WrapFrameId(StackFrame::Id id) { 6134 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); 6135 return Smi::FromInt(id >> 2); 6136} 6137 6138 6139static StackFrame::Id UnwrapFrameId(Smi* wrapped) { 6140 return static_cast<StackFrame::Id>(wrapped->value() << 2); 6141} 6142 6143 6144// Adds a JavaScript function as a debug event listener. 6145// args[0]: debug event listener function to set or null or undefined for 6146// clearing the event listener function 6147// args[1]: object supplied during callback 6148static Object* Runtime_SetDebugEventListener(Arguments args) { 6149 ASSERT(args.length() == 2); 6150 RUNTIME_ASSERT(args[0]->IsJSFunction() || 6151 args[0]->IsUndefined() || 6152 args[0]->IsNull()); 6153 Handle<Object> callback = args.at<Object>(0); 6154 Handle<Object> data = args.at<Object>(1); 6155 Debugger::SetEventListener(callback, data); 6156 6157 return Heap::undefined_value(); 6158} 6159 6160 6161static Object* Runtime_Break(Arguments args) { 6162 ASSERT(args.length() == 0); 6163 StackGuard::DebugBreak(); 6164 return Heap::undefined_value(); 6165} 6166 6167 6168static Object* DebugLookupResultValue(Object* receiver, String* name, 6169 LookupResult* result, 6170 bool* caught_exception) { 6171 Object* value; 6172 switch (result->type()) { 6173 case NORMAL: 6174 value = result->holder()->GetNormalizedProperty(result); 6175 if (value->IsTheHole()) { 6176 return Heap::undefined_value(); 6177 } 6178 return value; 6179 case FIELD: 6180 value = 6181 JSObject::cast( 6182 result->holder())->FastPropertyAt(result->GetFieldIndex()); 6183 if (value->IsTheHole()) { 6184 return Heap::undefined_value(); 6185 } 6186 return value; 6187 case CONSTANT_FUNCTION: 6188 return result->GetConstantFunction(); 6189 case CALLBACKS: { 6190 Object* structure = result->GetCallbackObject(); 6191 if (structure->IsProxy() || structure->IsAccessorInfo()) { 6192 value = receiver->GetPropertyWithCallback( 6193 receiver, structure, name, result->holder()); 6194 if (value->IsException()) { 6195 value = Top::pending_exception(); 6196 Top::clear_pending_exception(); 6197 if (caught_exception != NULL) { 6198 *caught_exception = true; 6199 } 6200 } 6201 return value; 6202 } else { 6203 return Heap::undefined_value(); 6204 } 6205 } 6206 case INTERCEPTOR: 6207 case MAP_TRANSITION: 6208 case CONSTANT_TRANSITION: 6209 case NULL_DESCRIPTOR: 6210 return Heap::undefined_value(); 6211 default: 6212 UNREACHABLE(); 6213 } 6214 UNREACHABLE(); 6215 return Heap::undefined_value(); 6216} 6217 6218 6219// Get debugger related details for an object property. 6220// args[0]: object holding property 6221// args[1]: name of the property 6222// 6223// The array returned contains the following information: 6224// 0: Property value 6225// 1: Property details 6226// 2: Property value is exception 6227// 3: Getter function if defined 6228// 4: Setter function if defined 6229// Items 2-4 are only filled if the property has either a getter or a setter 6230// defined through __defineGetter__ and/or __defineSetter__. 6231static Object* Runtime_DebugGetPropertyDetails(Arguments args) { 6232 HandleScope scope; 6233 6234 ASSERT(args.length() == 2); 6235 6236 CONVERT_ARG_CHECKED(JSObject, obj, 0); 6237 CONVERT_ARG_CHECKED(String, name, 1); 6238 6239 // Make sure to set the current context to the context before the debugger was 6240 // entered (if the debugger is entered). The reason for switching context here 6241 // is that for some property lookups (accessors and interceptors) callbacks 6242 // into the embedding application can occour, and the embedding application 6243 // could have the assumption that its own global context is the current 6244 // context and not some internal debugger context. 6245 SaveContext save; 6246 if (Debug::InDebugger()) { 6247 Top::set_context(*Debug::debugger_entry()->GetContext()); 6248 } 6249 6250 // Skip the global proxy as it has no properties and always delegates to the 6251 // real global object. 6252 if (obj->IsJSGlobalProxy()) { 6253 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 6254 } 6255 6256 6257 // Check if the name is trivially convertible to an index and get the element 6258 // if so. 6259 uint32_t index; 6260 if (name->AsArrayIndex(&index)) { 6261 Handle<FixedArray> details = Factory::NewFixedArray(2); 6262 details->set(0, Runtime::GetElementOrCharAt(obj, index)); 6263 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi()); 6264 return *Factory::NewJSArrayWithElements(details); 6265 } 6266 6267 // Find the number of objects making up this. 6268 int length = LocalPrototypeChainLength(*obj); 6269 6270 // Try local lookup on each of the objects. 6271 Handle<JSObject> jsproto = obj; 6272 for (int i = 0; i < length; i++) { 6273 LookupResult result; 6274 jsproto->LocalLookup(*name, &result); 6275 if (result.IsProperty()) { 6276 // LookupResult is not GC safe as it holds raw object pointers. 6277 // GC can happen later in this code so put the required fields into 6278 // local variables using handles when required for later use. 6279 PropertyType result_type = result.type(); 6280 Handle<Object> result_callback_obj; 6281 if (result_type == CALLBACKS) { 6282 result_callback_obj = Handle<Object>(result.GetCallbackObject()); 6283 } 6284 Smi* property_details = result.GetPropertyDetails().AsSmi(); 6285 // DebugLookupResultValue can cause GC so details from LookupResult needs 6286 // to be copied to handles before this. 6287 bool caught_exception = false; 6288 Object* raw_value = DebugLookupResultValue(*obj, *name, &result, 6289 &caught_exception); 6290 if (raw_value->IsFailure()) return raw_value; 6291 Handle<Object> value(raw_value); 6292 6293 // If the callback object is a fixed array then it contains JavaScript 6294 // getter and/or setter. 6295 bool hasJavaScriptAccessors = result_type == CALLBACKS && 6296 result_callback_obj->IsFixedArray(); 6297 Handle<FixedArray> details = 6298 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2); 6299 details->set(0, *value); 6300 details->set(1, property_details); 6301 if (hasJavaScriptAccessors) { 6302 details->set(2, 6303 caught_exception ? Heap::true_value() 6304 : Heap::false_value()); 6305 details->set(3, FixedArray::cast(*result_callback_obj)->get(0)); 6306 details->set(4, FixedArray::cast(*result_callback_obj)->get(1)); 6307 } 6308 6309 return *Factory::NewJSArrayWithElements(details); 6310 } 6311 if (i < length - 1) { 6312 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 6313 } 6314 } 6315 6316 return Heap::undefined_value(); 6317} 6318 6319 6320static Object* Runtime_DebugGetProperty(Arguments args) { 6321 HandleScope scope; 6322 6323 ASSERT(args.length() == 2); 6324 6325 CONVERT_ARG_CHECKED(JSObject, obj, 0); 6326 CONVERT_ARG_CHECKED(String, name, 1); 6327 6328 LookupResult result; 6329 obj->Lookup(*name, &result); 6330 if (result.IsProperty()) { 6331 return DebugLookupResultValue(*obj, *name, &result, NULL); 6332 } 6333 return Heap::undefined_value(); 6334} 6335 6336 6337// Return the property type calculated from the property details. 6338// args[0]: smi with property details. 6339static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) { 6340 ASSERT(args.length() == 1); 6341 CONVERT_CHECKED(Smi, details, args[0]); 6342 PropertyType type = PropertyDetails(details).type(); 6343 return Smi::FromInt(static_cast<int>(type)); 6344} 6345 6346 6347// Return the property attribute calculated from the property details. 6348// args[0]: smi with property details. 6349static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) { 6350 ASSERT(args.length() == 1); 6351 CONVERT_CHECKED(Smi, details, args[0]); 6352 PropertyAttributes attributes = PropertyDetails(details).attributes(); 6353 return Smi::FromInt(static_cast<int>(attributes)); 6354} 6355 6356 6357// Return the property insertion index calculated from the property details. 6358// args[0]: smi with property details. 6359static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) { 6360 ASSERT(args.length() == 1); 6361 CONVERT_CHECKED(Smi, details, args[0]); 6362 int index = PropertyDetails(details).index(); 6363 return Smi::FromInt(index); 6364} 6365 6366 6367// Return property value from named interceptor. 6368// args[0]: object 6369// args[1]: property name 6370static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) { 6371 HandleScope scope; 6372 ASSERT(args.length() == 2); 6373 CONVERT_ARG_CHECKED(JSObject, obj, 0); 6374 RUNTIME_ASSERT(obj->HasNamedInterceptor()); 6375 CONVERT_ARG_CHECKED(String, name, 1); 6376 6377 PropertyAttributes attributes; 6378 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes); 6379} 6380 6381 6382// Return element value from indexed interceptor. 6383// args[0]: object 6384// args[1]: index 6385static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) { 6386 HandleScope scope; 6387 ASSERT(args.length() == 2); 6388 CONVERT_ARG_CHECKED(JSObject, obj, 0); 6389 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); 6390 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); 6391 6392 return obj->GetElementWithInterceptor(*obj, index); 6393} 6394 6395 6396static Object* Runtime_CheckExecutionState(Arguments args) { 6397 ASSERT(args.length() >= 1); 6398 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 6399 // Check that the break id is valid. 6400 if (Debug::break_id() == 0 || break_id != Debug::break_id()) { 6401 return Top::Throw(Heap::illegal_execution_state_symbol()); 6402 } 6403 6404 return Heap::true_value(); 6405} 6406 6407 6408static Object* Runtime_GetFrameCount(Arguments args) { 6409 HandleScope scope; 6410 ASSERT(args.length() == 1); 6411 6412 // Check arguments. 6413 Object* result = Runtime_CheckExecutionState(args); 6414 if (result->IsFailure()) return result; 6415 6416 // Count all frames which are relevant to debugging stack trace. 6417 int n = 0; 6418 StackFrame::Id id = Debug::break_frame_id(); 6419 if (id == StackFrame::NO_ID) { 6420 // If there is no JavaScript stack frame count is 0. 6421 return Smi::FromInt(0); 6422 } 6423 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++; 6424 return Smi::FromInt(n); 6425} 6426 6427 6428static const int kFrameDetailsFrameIdIndex = 0; 6429static const int kFrameDetailsReceiverIndex = 1; 6430static const int kFrameDetailsFunctionIndex = 2; 6431static const int kFrameDetailsArgumentCountIndex = 3; 6432static const int kFrameDetailsLocalCountIndex = 4; 6433static const int kFrameDetailsSourcePositionIndex = 5; 6434static const int kFrameDetailsConstructCallIndex = 6; 6435static const int kFrameDetailsDebuggerFrameIndex = 7; 6436static const int kFrameDetailsFirstDynamicIndex = 8; 6437 6438// Return an array with frame details 6439// args[0]: number: break id 6440// args[1]: number: frame index 6441// 6442// The array returned contains the following information: 6443// 0: Frame id 6444// 1: Receiver 6445// 2: Function 6446// 3: Argument count 6447// 4: Local count 6448// 5: Source position 6449// 6: Constructor call 6450// 7: Debugger frame 6451// Arguments name, value 6452// Locals name, value 6453static Object* Runtime_GetFrameDetails(Arguments args) { 6454 HandleScope scope; 6455 ASSERT(args.length() == 2); 6456 6457 // Check arguments. 6458 Object* check = Runtime_CheckExecutionState(args); 6459 if (check->IsFailure()) return check; 6460 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 6461 6462 // Find the relevant frame with the requested index. 6463 StackFrame::Id id = Debug::break_frame_id(); 6464 if (id == StackFrame::NO_ID) { 6465 // If there are no JavaScript stack frames return undefined. 6466 return Heap::undefined_value(); 6467 } 6468 int count = 0; 6469 JavaScriptFrameIterator it(id); 6470 for (; !it.done(); it.Advance()) { 6471 if (count == index) break; 6472 count++; 6473 } 6474 if (it.done()) return Heap::undefined_value(); 6475 6476 // Traverse the saved contexts chain to find the active context for the 6477 // selected frame. 6478 SaveContext* save = Top::save_context(); 6479 while (save != NULL && !save->below(it.frame())) { 6480 save = save->prev(); 6481 } 6482 ASSERT(save != NULL); 6483 6484 // Get the frame id. 6485 Handle<Object> frame_id(WrapFrameId(it.frame()->id())); 6486 6487 // Find source position. 6488 int position = it.frame()->code()->SourcePosition(it.frame()->pc()); 6489 6490 // Check for constructor frame. 6491 bool constructor = it.frame()->IsConstructor(); 6492 6493 // Get code and read scope info from it for local variable information. 6494 Handle<Code> code(it.frame()->code()); 6495 ScopeInfo<> info(*code); 6496 6497 // Get the context. 6498 Handle<Context> context(Context::cast(it.frame()->context())); 6499 6500 // Get the locals names and values into a temporary array. 6501 // 6502 // TODO(1240907): Hide compiler-introduced stack variables 6503 // (e.g. .result)? For users of the debugger, they will probably be 6504 // confusing. 6505 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2); 6506 for (int i = 0; i < info.NumberOfLocals(); i++) { 6507 // Name of the local. 6508 locals->set(i * 2, *info.LocalName(i)); 6509 6510 // Fetch the value of the local - either from the stack or from a 6511 // heap-allocated context. 6512 if (i < info.number_of_stack_slots()) { 6513 locals->set(i * 2 + 1, it.frame()->GetExpression(i)); 6514 } else { 6515 Handle<String> name = info.LocalName(i); 6516 // Traverse the context chain to the function context as all local 6517 // variables stored in the context will be on the function context. 6518 while (!context->is_function_context()) { 6519 context = Handle<Context>(context->previous()); 6520 } 6521 ASSERT(context->is_function_context()); 6522 locals->set(i * 2 + 1, 6523 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name, 6524 NULL))); 6525 } 6526 } 6527 6528 // Now advance to the arguments adapter frame (if any). If contains all 6529 // the provided parameters and 6530 6531 // Now advance to the arguments adapter frame (if any). It contains all 6532 // the provided parameters whereas the function frame always have the number 6533 // of arguments matching the functions parameters. The rest of the 6534 // information (except for what is collected above) is the same. 6535 it.AdvanceToArgumentsFrame(); 6536 6537 // Find the number of arguments to fill. At least fill the number of 6538 // parameters for the function and fill more if more parameters are provided. 6539 int argument_count = info.number_of_parameters(); 6540 if (argument_count < it.frame()->GetProvidedParametersCount()) { 6541 argument_count = it.frame()->GetProvidedParametersCount(); 6542 } 6543 6544 // Calculate the size of the result. 6545 int details_size = kFrameDetailsFirstDynamicIndex + 6546 2 * (argument_count + info.NumberOfLocals()); 6547 Handle<FixedArray> details = Factory::NewFixedArray(details_size); 6548 6549 // Add the frame id. 6550 details->set(kFrameDetailsFrameIdIndex, *frame_id); 6551 6552 // Add the function (same as in function frame). 6553 details->set(kFrameDetailsFunctionIndex, it.frame()->function()); 6554 6555 // Add the arguments count. 6556 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); 6557 6558 // Add the locals count 6559 details->set(kFrameDetailsLocalCountIndex, 6560 Smi::FromInt(info.NumberOfLocals())); 6561 6562 // Add the source position. 6563 if (position != RelocInfo::kNoPosition) { 6564 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 6565 } else { 6566 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value()); 6567 } 6568 6569 // Add the constructor information. 6570 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor)); 6571 6572 // Add information on whether this frame is invoked in the debugger context. 6573 details->set(kFrameDetailsDebuggerFrameIndex, 6574 Heap::ToBoolean(*save->context() == *Debug::debug_context())); 6575 6576 // Fill the dynamic part. 6577 int details_index = kFrameDetailsFirstDynamicIndex; 6578 6579 // Add arguments name and value. 6580 for (int i = 0; i < argument_count; i++) { 6581 // Name of the argument. 6582 if (i < info.number_of_parameters()) { 6583 details->set(details_index++, *info.parameter_name(i)); 6584 } else { 6585 details->set(details_index++, Heap::undefined_value()); 6586 } 6587 6588 // Parameter value. 6589 if (i < it.frame()->GetProvidedParametersCount()) { 6590 details->set(details_index++, it.frame()->GetParameter(i)); 6591 } else { 6592 details->set(details_index++, Heap::undefined_value()); 6593 } 6594 } 6595 6596 // Add locals name and value from the temporary copy from the function frame. 6597 for (int i = 0; i < info.NumberOfLocals() * 2; i++) { 6598 details->set(details_index++, locals->get(i)); 6599 } 6600 6601 // Add the receiver (same as in function frame). 6602 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE 6603 // THE FRAME ITERATOR TO WRAP THE RECEIVER. 6604 Handle<Object> receiver(it.frame()->receiver()); 6605 if (!receiver->IsJSObject()) { 6606 // If the receiver is NOT a JSObject we have hit an optimization 6607 // where a value object is not converted into a wrapped JS objects. 6608 // To hide this optimization from the debugger, we wrap the receiver 6609 // by creating correct wrapper object based on the calling frame's 6610 // global context. 6611 it.Advance(); 6612 Handle<Context> calling_frames_global_context( 6613 Context::cast(Context::cast(it.frame()->context())->global_context())); 6614 receiver = Factory::ToObject(receiver, calling_frames_global_context); 6615 } 6616 details->set(kFrameDetailsReceiverIndex, *receiver); 6617 6618 ASSERT_EQ(details_size, details_index); 6619 return *Factory::NewJSArrayWithElements(details); 6620} 6621 6622 6623// Copy all the context locals into an object used to materialize a scope. 6624static void CopyContextLocalsToScopeObject(Handle<Code> code, 6625 ScopeInfo<>& scope_info, 6626 Handle<Context> context, 6627 Handle<JSObject> scope_object) { 6628 // Fill all context locals to the context extension. 6629 for (int i = Context::MIN_CONTEXT_SLOTS; 6630 i < scope_info.number_of_context_slots(); 6631 i++) { 6632 int context_index = 6633 ScopeInfo<>::ContextSlotIndex(*code, 6634 *scope_info.context_slot_name(i), 6635 NULL); 6636 6637 // Don't include the arguments shadow (.arguments) context variable. 6638 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) { 6639 SetProperty(scope_object, 6640 scope_info.context_slot_name(i), 6641 Handle<Object>(context->get(context_index)), NONE); 6642 } 6643 } 6644} 6645 6646 6647// Create a plain JSObject which materializes the local scope for the specified 6648// frame. 6649static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) { 6650 Handle<JSFunction> function(JSFunction::cast(frame->function())); 6651 Handle<Code> code(function->code()); 6652 ScopeInfo<> scope_info(*code); 6653 6654 // Allocate and initialize a JSObject with all the arguments, stack locals 6655 // heap locals and extension properties of the debugged function. 6656 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function()); 6657 6658 // First fill all parameters. 6659 for (int i = 0; i < scope_info.number_of_parameters(); ++i) { 6660 SetProperty(local_scope, 6661 scope_info.parameter_name(i), 6662 Handle<Object>(frame->GetParameter(i)), NONE); 6663 } 6664 6665 // Second fill all stack locals. 6666 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) { 6667 SetProperty(local_scope, 6668 scope_info.stack_slot_name(i), 6669 Handle<Object>(frame->GetExpression(i)), NONE); 6670 } 6671 6672 // Third fill all context locals. 6673 Handle<Context> frame_context(Context::cast(frame->context())); 6674 Handle<Context> function_context(frame_context->fcontext()); 6675 CopyContextLocalsToScopeObject(code, scope_info, 6676 function_context, local_scope); 6677 6678 // Finally copy any properties from the function context extension. This will 6679 // be variables introduced by eval. 6680 if (function_context->closure() == *function) { 6681 if (function_context->has_extension() && 6682 !function_context->IsGlobalContext()) { 6683 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 6684 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); 6685 for (int i = 0; i < keys->length(); i++) { 6686 // Names of variables introduced by eval are strings. 6687 ASSERT(keys->get(i)->IsString()); 6688 Handle<String> key(String::cast(keys->get(i))); 6689 SetProperty(local_scope, key, GetProperty(ext, key), NONE); 6690 } 6691 } 6692 } 6693 return local_scope; 6694} 6695 6696 6697// Create a plain JSObject which materializes the closure content for the 6698// context. 6699static Handle<JSObject> MaterializeClosure(Handle<Context> context) { 6700 ASSERT(context->is_function_context()); 6701 6702 Handle<Code> code(context->closure()->code()); 6703 ScopeInfo<> scope_info(*code); 6704 6705 // Allocate and initialize a JSObject with all the content of theis function 6706 // closure. 6707 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function()); 6708 6709 // Check whether the arguments shadow object exists. 6710 int arguments_shadow_index = 6711 ScopeInfo<>::ContextSlotIndex(*code, 6712 Heap::arguments_shadow_symbol(), 6713 NULL); 6714 if (arguments_shadow_index >= 0) { 6715 // In this case all the arguments are available in the arguments shadow 6716 // object. 6717 Handle<JSObject> arguments_shadow( 6718 JSObject::cast(context->get(arguments_shadow_index))); 6719 for (int i = 0; i < scope_info.number_of_parameters(); ++i) { 6720 SetProperty(closure_scope, 6721 scope_info.parameter_name(i), 6722 Handle<Object>(arguments_shadow->GetElement(i)), NONE); 6723 } 6724 } 6725 6726 // Fill all context locals to the context extension. 6727 CopyContextLocalsToScopeObject(code, scope_info, context, closure_scope); 6728 6729 // Finally copy any properties from the function context extension. This will 6730 // be variables introduced by eval. 6731 if (context->has_extension()) { 6732 Handle<JSObject> ext(JSObject::cast(context->extension())); 6733 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); 6734 for (int i = 0; i < keys->length(); i++) { 6735 // Names of variables introduced by eval are strings. 6736 ASSERT(keys->get(i)->IsString()); 6737 Handle<String> key(String::cast(keys->get(i))); 6738 SetProperty(closure_scope, key, GetProperty(ext, key), NONE); 6739 } 6740 } 6741 6742 return closure_scope; 6743} 6744 6745 6746// Iterate over the actual scopes visible from a stack frame. All scopes are 6747// backed by an actual context except the local scope, which is inserted 6748// "artifically" in the context chain. 6749class ScopeIterator { 6750 public: 6751 enum ScopeType { 6752 ScopeTypeGlobal = 0, 6753 ScopeTypeLocal, 6754 ScopeTypeWith, 6755 ScopeTypeClosure, 6756 // Every catch block contains an implicit with block (its parameter is 6757 // a JSContextExtensionObject) that extends current scope with a variable 6758 // holding exception object. Such with blocks are treated as scopes of their 6759 // own type. 6760 ScopeTypeCatch 6761 }; 6762 6763 explicit ScopeIterator(JavaScriptFrame* frame) 6764 : frame_(frame), 6765 function_(JSFunction::cast(frame->function())), 6766 context_(Context::cast(frame->context())), 6767 local_done_(false), 6768 at_local_(false) { 6769 6770 // Check whether the first scope is actually a local scope. 6771 if (context_->IsGlobalContext()) { 6772 // If there is a stack slot for .result then this local scope has been 6773 // created for evaluating top level code and it is not a real local scope. 6774 // Checking for the existence of .result seems fragile, but the scope info 6775 // saved with the code object does not otherwise have that information. 6776 Handle<Code> code(function_->code()); 6777 int index = ScopeInfo<>::StackSlotIndex(*code, Heap::result_symbol()); 6778 at_local_ = index < 0; 6779 } else if (context_->is_function_context()) { 6780 at_local_ = true; 6781 } 6782 } 6783 6784 // More scopes? 6785 bool Done() { return context_.is_null(); } 6786 6787 // Move to the next scope. 6788 void Next() { 6789 // If at a local scope mark the local scope as passed. 6790 if (at_local_) { 6791 at_local_ = false; 6792 local_done_ = true; 6793 6794 // If the current context is not associated with the local scope the 6795 // current context is the next real scope, so don't move to the next 6796 // context in this case. 6797 if (context_->closure() != *function_) { 6798 return; 6799 } 6800 } 6801 6802 // The global scope is always the last in the chain. 6803 if (context_->IsGlobalContext()) { 6804 context_ = Handle<Context>(); 6805 return; 6806 } 6807 6808 // Move to the next context. 6809 if (context_->is_function_context()) { 6810 context_ = Handle<Context>(Context::cast(context_->closure()->context())); 6811 } else { 6812 context_ = Handle<Context>(context_->previous()); 6813 } 6814 6815 // If passing the local scope indicate that the current scope is now the 6816 // local scope. 6817 if (!local_done_ && 6818 (context_->IsGlobalContext() || (context_->is_function_context()))) { 6819 at_local_ = true; 6820 } 6821 } 6822 6823 // Return the type of the current scope. 6824 int Type() { 6825 if (at_local_) { 6826 return ScopeTypeLocal; 6827 } 6828 if (context_->IsGlobalContext()) { 6829 ASSERT(context_->global()->IsGlobalObject()); 6830 return ScopeTypeGlobal; 6831 } 6832 if (context_->is_function_context()) { 6833 return ScopeTypeClosure; 6834 } 6835 ASSERT(context_->has_extension()); 6836 // Current scope is either an explicit with statement or a with statement 6837 // implicitely generated for a catch block. 6838 // If the extension object here is a JSContextExtensionObject then 6839 // current with statement is one frome a catch block otherwise it's a 6840 // regular with statement. 6841 if (context_->extension()->IsJSContextExtensionObject()) { 6842 return ScopeTypeCatch; 6843 } 6844 return ScopeTypeWith; 6845 } 6846 6847 // Return the JavaScript object with the content of the current scope. 6848 Handle<JSObject> ScopeObject() { 6849 switch (Type()) { 6850 case ScopeIterator::ScopeTypeGlobal: 6851 return Handle<JSObject>(CurrentContext()->global()); 6852 break; 6853 case ScopeIterator::ScopeTypeLocal: 6854 // Materialize the content of the local scope into a JSObject. 6855 return MaterializeLocalScope(frame_); 6856 break; 6857 case ScopeIterator::ScopeTypeWith: 6858 case ScopeIterator::ScopeTypeCatch: 6859 // Return the with object. 6860 return Handle<JSObject>(CurrentContext()->extension()); 6861 break; 6862 case ScopeIterator::ScopeTypeClosure: 6863 // Materialize the content of the closure scope into a JSObject. 6864 return MaterializeClosure(CurrentContext()); 6865 break; 6866 } 6867 UNREACHABLE(); 6868 return Handle<JSObject>(); 6869 } 6870 6871 // Return the context for this scope. For the local context there might not 6872 // be an actual context. 6873 Handle<Context> CurrentContext() { 6874 if (at_local_ && context_->closure() != *function_) { 6875 return Handle<Context>(); 6876 } 6877 return context_; 6878 } 6879 6880#ifdef DEBUG 6881 // Debug print of the content of the current scope. 6882 void DebugPrint() { 6883 switch (Type()) { 6884 case ScopeIterator::ScopeTypeGlobal: 6885 PrintF("Global:\n"); 6886 CurrentContext()->Print(); 6887 break; 6888 6889 case ScopeIterator::ScopeTypeLocal: { 6890 PrintF("Local:\n"); 6891 Handle<Code> code(function_->code()); 6892 ScopeInfo<> scope_info(*code); 6893 scope_info.Print(); 6894 if (!CurrentContext().is_null()) { 6895 CurrentContext()->Print(); 6896 if (CurrentContext()->has_extension()) { 6897 Handle<JSObject> extension = 6898 Handle<JSObject>(CurrentContext()->extension()); 6899 if (extension->IsJSContextExtensionObject()) { 6900 extension->Print(); 6901 } 6902 } 6903 } 6904 break; 6905 } 6906 6907 case ScopeIterator::ScopeTypeWith: { 6908 PrintF("With:\n"); 6909 Handle<JSObject> extension = 6910 Handle<JSObject>(CurrentContext()->extension()); 6911 extension->Print(); 6912 break; 6913 } 6914 6915 case ScopeIterator::ScopeTypeCatch: { 6916 PrintF("Catch:\n"); 6917 Handle<JSObject> extension = 6918 Handle<JSObject>(CurrentContext()->extension()); 6919 extension->Print(); 6920 break; 6921 } 6922 6923 case ScopeIterator::ScopeTypeClosure: { 6924 PrintF("Closure:\n"); 6925 CurrentContext()->Print(); 6926 if (CurrentContext()->has_extension()) { 6927 Handle<JSObject> extension = 6928 Handle<JSObject>(CurrentContext()->extension()); 6929 if (extension->IsJSContextExtensionObject()) { 6930 extension->Print(); 6931 } 6932 } 6933 break; 6934 } 6935 6936 default: 6937 UNREACHABLE(); 6938 } 6939 PrintF("\n"); 6940 } 6941#endif 6942 6943 private: 6944 JavaScriptFrame* frame_; 6945 Handle<JSFunction> function_; 6946 Handle<Context> context_; 6947 bool local_done_; 6948 bool at_local_; 6949 6950 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); 6951}; 6952 6953 6954static Object* Runtime_GetScopeCount(Arguments args) { 6955 HandleScope scope; 6956 ASSERT(args.length() == 2); 6957 6958 // Check arguments. 6959 Object* check = Runtime_CheckExecutionState(args); 6960 if (check->IsFailure()) return check; 6961 CONVERT_CHECKED(Smi, wrapped_id, args[1]); 6962 6963 // Get the frame where the debugging is performed. 6964 StackFrame::Id id = UnwrapFrameId(wrapped_id); 6965 JavaScriptFrameIterator it(id); 6966 JavaScriptFrame* frame = it.frame(); 6967 6968 // Count the visible scopes. 6969 int n = 0; 6970 for (ScopeIterator it(frame); !it.Done(); it.Next()) { 6971 n++; 6972 } 6973 6974 return Smi::FromInt(n); 6975} 6976 6977 6978static const int kScopeDetailsTypeIndex = 0; 6979static const int kScopeDetailsObjectIndex = 1; 6980static const int kScopeDetailsSize = 2; 6981 6982// Return an array with scope details 6983// args[0]: number: break id 6984// args[1]: number: frame index 6985// args[2]: number: scope index 6986// 6987// The array returned contains the following information: 6988// 0: Scope type 6989// 1: Scope object 6990static Object* Runtime_GetScopeDetails(Arguments args) { 6991 HandleScope scope; 6992 ASSERT(args.length() == 3); 6993 6994 // Check arguments. 6995 Object* check = Runtime_CheckExecutionState(args); 6996 if (check->IsFailure()) return check; 6997 CONVERT_CHECKED(Smi, wrapped_id, args[1]); 6998 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]); 6999 7000 // Get the frame where the debugging is performed. 7001 StackFrame::Id id = UnwrapFrameId(wrapped_id); 7002 JavaScriptFrameIterator frame_it(id); 7003 JavaScriptFrame* frame = frame_it.frame(); 7004 7005 // Find the requested scope. 7006 int n = 0; 7007 ScopeIterator it(frame); 7008 for (; !it.Done() && n < index; it.Next()) { 7009 n++; 7010 } 7011 if (it.Done()) { 7012 return Heap::undefined_value(); 7013 } 7014 7015 // Calculate the size of the result. 7016 int details_size = kScopeDetailsSize; 7017 Handle<FixedArray> details = Factory::NewFixedArray(details_size); 7018 7019 // Fill in scope details. 7020 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type())); 7021 details->set(kScopeDetailsObjectIndex, *it.ScopeObject()); 7022 7023 return *Factory::NewJSArrayWithElements(details); 7024} 7025 7026 7027static Object* Runtime_DebugPrintScopes(Arguments args) { 7028 HandleScope scope; 7029 ASSERT(args.length() == 0); 7030 7031#ifdef DEBUG 7032 // Print the scopes for the top frame. 7033 StackFrameLocator locator; 7034 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 7035 for (ScopeIterator it(frame); !it.Done(); it.Next()) { 7036 it.DebugPrint(); 7037 } 7038#endif 7039 return Heap::undefined_value(); 7040} 7041 7042 7043static Object* Runtime_GetCFrames(Arguments args) { 7044 HandleScope scope; 7045 ASSERT(args.length() == 1); 7046 Object* result = Runtime_CheckExecutionState(args); 7047 if (result->IsFailure()) return result; 7048 7049#if V8_HOST_ARCH_64_BIT 7050 UNIMPLEMENTED(); 7051 return Heap::undefined_value(); 7052#else 7053 7054 static const int kMaxCFramesSize = 200; 7055 ScopedVector<OS::StackFrame> frames(kMaxCFramesSize); 7056 int frames_count = OS::StackWalk(frames); 7057 if (frames_count == OS::kStackWalkError) { 7058 return Heap::undefined_value(); 7059 } 7060 7061 Handle<String> address_str = Factory::LookupAsciiSymbol("address"); 7062 Handle<String> text_str = Factory::LookupAsciiSymbol("text"); 7063 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count); 7064 for (int i = 0; i < frames_count; i++) { 7065 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function()); 7066 frame_value->SetProperty( 7067 *address_str, 7068 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)), 7069 NONE); 7070 7071 // Get the stack walk text for this frame. 7072 Handle<String> frame_text; 7073 int frame_text_length = StrLength(frames[i].text); 7074 if (frame_text_length > 0) { 7075 Vector<const char> str(frames[i].text, frame_text_length); 7076 frame_text = Factory::NewStringFromAscii(str); 7077 } 7078 7079 if (!frame_text.is_null()) { 7080 frame_value->SetProperty(*text_str, *frame_text, NONE); 7081 } 7082 7083 frames_array->set(i, *frame_value); 7084 } 7085 return *Factory::NewJSArrayWithElements(frames_array); 7086#endif // V8_HOST_ARCH_64_BIT 7087} 7088 7089 7090static Object* Runtime_GetThreadCount(Arguments args) { 7091 HandleScope scope; 7092 ASSERT(args.length() == 1); 7093 7094 // Check arguments. 7095 Object* result = Runtime_CheckExecutionState(args); 7096 if (result->IsFailure()) return result; 7097 7098 // Count all archived V8 threads. 7099 int n = 0; 7100 for (ThreadState* thread = ThreadState::FirstInUse(); 7101 thread != NULL; 7102 thread = thread->Next()) { 7103 n++; 7104 } 7105 7106 // Total number of threads is current thread and archived threads. 7107 return Smi::FromInt(n + 1); 7108} 7109 7110 7111static const int kThreadDetailsCurrentThreadIndex = 0; 7112static const int kThreadDetailsThreadIdIndex = 1; 7113static const int kThreadDetailsSize = 2; 7114 7115// Return an array with thread details 7116// args[0]: number: break id 7117// args[1]: number: thread index 7118// 7119// The array returned contains the following information: 7120// 0: Is current thread? 7121// 1: Thread id 7122static Object* Runtime_GetThreadDetails(Arguments args) { 7123 HandleScope scope; 7124 ASSERT(args.length() == 2); 7125 7126 // Check arguments. 7127 Object* check = Runtime_CheckExecutionState(args); 7128 if (check->IsFailure()) return check; 7129 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 7130 7131 // Allocate array for result. 7132 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize); 7133 7134 // Thread index 0 is current thread. 7135 if (index == 0) { 7136 // Fill the details. 7137 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value()); 7138 details->set(kThreadDetailsThreadIdIndex, 7139 Smi::FromInt(ThreadManager::CurrentId())); 7140 } else { 7141 // Find the thread with the requested index. 7142 int n = 1; 7143 ThreadState* thread = ThreadState::FirstInUse(); 7144 while (index != n && thread != NULL) { 7145 thread = thread->Next(); 7146 n++; 7147 } 7148 if (thread == NULL) { 7149 return Heap::undefined_value(); 7150 } 7151 7152 // Fill the details. 7153 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value()); 7154 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id())); 7155 } 7156 7157 // Convert to JS array and return. 7158 return *Factory::NewJSArrayWithElements(details); 7159} 7160 7161 7162static Object* Runtime_GetBreakLocations(Arguments args) { 7163 HandleScope scope; 7164 ASSERT(args.length() == 1); 7165 7166 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 7167 Handle<SharedFunctionInfo> shared(fun->shared()); 7168 // Find the number of break points 7169 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared); 7170 if (break_locations->IsUndefined()) return Heap::undefined_value(); 7171 // Return array as JS array 7172 return *Factory::NewJSArrayWithElements( 7173 Handle<FixedArray>::cast(break_locations)); 7174} 7175 7176 7177// Set a break point in a function 7178// args[0]: function 7179// args[1]: number: break source position (within the function source) 7180// args[2]: number: break point object 7181static Object* Runtime_SetFunctionBreakPoint(Arguments args) { 7182 HandleScope scope; 7183 ASSERT(args.length() == 3); 7184 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 7185 Handle<SharedFunctionInfo> shared(fun->shared()); 7186 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 7187 RUNTIME_ASSERT(source_position >= 0); 7188 Handle<Object> break_point_object_arg = args.at<Object>(2); 7189 7190 // Set break point. 7191 Debug::SetBreakPoint(shared, source_position, break_point_object_arg); 7192 7193 return Heap::undefined_value(); 7194} 7195 7196 7197Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script, 7198 int position) { 7199 // Iterate the heap looking for SharedFunctionInfo generated from the 7200 // script. The inner most SharedFunctionInfo containing the source position 7201 // for the requested break point is found. 7202 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo 7203 // which is found is not compiled it is compiled and the heap is iterated 7204 // again as the compilation might create inner functions from the newly 7205 // compiled function and the actual requested break point might be in one of 7206 // these functions. 7207 bool done = false; 7208 // The current candidate for the source position: 7209 int target_start_position = RelocInfo::kNoPosition; 7210 Handle<SharedFunctionInfo> target; 7211 // The current candidate for the last function in script: 7212 Handle<SharedFunctionInfo> last; 7213 while (!done) { 7214 HeapIterator iterator; 7215 for (HeapObject* obj = iterator.next(); 7216 obj != NULL; obj = iterator.next()) { 7217 if (obj->IsSharedFunctionInfo()) { 7218 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj)); 7219 if (shared->script() == *script) { 7220 // If the SharedFunctionInfo found has the requested script data and 7221 // contains the source position it is a candidate. 7222 int start_position = shared->function_token_position(); 7223 if (start_position == RelocInfo::kNoPosition) { 7224 start_position = shared->start_position(); 7225 } 7226 if (start_position <= position && 7227 position <= shared->end_position()) { 7228 // If there is no candidate or this function is within the current 7229 // candidate this is the new candidate. 7230 if (target.is_null()) { 7231 target_start_position = start_position; 7232 target = shared; 7233 } else { 7234 if (target_start_position == start_position && 7235 shared->end_position() == target->end_position()) { 7236 // If a top-level function contain only one function 7237 // declartion the source for the top-level and the function is 7238 // the same. In that case prefer the non top-level function. 7239 if (!shared->is_toplevel()) { 7240 target_start_position = start_position; 7241 target = shared; 7242 } 7243 } else if (target_start_position <= start_position && 7244 shared->end_position() <= target->end_position()) { 7245 // This containment check includes equality as a function inside 7246 // a top-level function can share either start or end position 7247 // with the top-level function. 7248 target_start_position = start_position; 7249 target = shared; 7250 } 7251 } 7252 } 7253 7254 // Keep track of the last function in the script. 7255 if (last.is_null() || 7256 shared->end_position() > last->start_position()) { 7257 last = shared; 7258 } 7259 } 7260 } 7261 } 7262 7263 // Make sure some candidate is selected. 7264 if (target.is_null()) { 7265 if (!last.is_null()) { 7266 // Position after the last function - use last. 7267 target = last; 7268 } else { 7269 // Unable to find function - possibly script without any function. 7270 return Heap::undefined_value(); 7271 } 7272 } 7273 7274 // If the candidate found is compiled we are done. NOTE: when lazy 7275 // compilation of inner functions is introduced some additional checking 7276 // needs to be done here to compile inner functions. 7277 done = target->is_compiled(); 7278 if (!done) { 7279 // If the candidate is not compiled compile it to reveal any inner 7280 // functions which might contain the requested source position. 7281 CompileLazyShared(target, KEEP_EXCEPTION, 0); 7282 } 7283 } 7284 7285 return *target; 7286} 7287 7288 7289// Change the state of a break point in a script. NOTE: Regarding performance 7290// see the NOTE for GetScriptFromScriptData. 7291// args[0]: script to set break point in 7292// args[1]: number: break source position (within the script source) 7293// args[2]: number: break point object 7294static Object* Runtime_SetScriptBreakPoint(Arguments args) { 7295 HandleScope scope; 7296 ASSERT(args.length() == 3); 7297 CONVERT_ARG_CHECKED(JSValue, wrapper, 0); 7298 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 7299 RUNTIME_ASSERT(source_position >= 0); 7300 Handle<Object> break_point_object_arg = args.at<Object>(2); 7301 7302 // Get the script from the script wrapper. 7303 RUNTIME_ASSERT(wrapper->value()->IsScript()); 7304 Handle<Script> script(Script::cast(wrapper->value())); 7305 7306 Object* result = Runtime::FindSharedFunctionInfoInScript( 7307 script, source_position); 7308 if (!result->IsUndefined()) { 7309 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result)); 7310 // Find position within function. The script position might be before the 7311 // source position of the first function. 7312 int position; 7313 if (shared->start_position() > source_position) { 7314 position = 0; 7315 } else { 7316 position = source_position - shared->start_position(); 7317 } 7318 Debug::SetBreakPoint(shared, position, break_point_object_arg); 7319 } 7320 return Heap::undefined_value(); 7321} 7322 7323 7324// Clear a break point 7325// args[0]: number: break point object 7326static Object* Runtime_ClearBreakPoint(Arguments args) { 7327 HandleScope scope; 7328 ASSERT(args.length() == 1); 7329 Handle<Object> break_point_object_arg = args.at<Object>(0); 7330 7331 // Clear break point. 7332 Debug::ClearBreakPoint(break_point_object_arg); 7333 7334 return Heap::undefined_value(); 7335} 7336 7337 7338// Change the state of break on exceptions 7339// args[0]: boolean indicating uncaught exceptions 7340// args[1]: boolean indicating on/off 7341static Object* Runtime_ChangeBreakOnException(Arguments args) { 7342 HandleScope scope; 7343 ASSERT(args.length() == 2); 7344 ASSERT(args[0]->IsNumber()); 7345 ASSERT(args[1]->IsBoolean()); 7346 7347 // Update break point state 7348 ExceptionBreakType type = 7349 static_cast<ExceptionBreakType>(NumberToUint32(args[0])); 7350 bool enable = args[1]->ToBoolean()->IsTrue(); 7351 Debug::ChangeBreakOnException(type, enable); 7352 return Heap::undefined_value(); 7353} 7354 7355 7356// Prepare for stepping 7357// args[0]: break id for checking execution state 7358// args[1]: step action from the enumeration StepAction 7359// args[2]: number of times to perform the step, for step out it is the number 7360// of frames to step down. 7361static Object* Runtime_PrepareStep(Arguments args) { 7362 HandleScope scope; 7363 ASSERT(args.length() == 3); 7364 // Check arguments. 7365 Object* check = Runtime_CheckExecutionState(args); 7366 if (check->IsFailure()) return check; 7367 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { 7368 return Top::Throw(Heap::illegal_argument_symbol()); 7369 } 7370 7371 // Get the step action and check validity. 7372 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); 7373 if (step_action != StepIn && 7374 step_action != StepNext && 7375 step_action != StepOut && 7376 step_action != StepInMin && 7377 step_action != StepMin) { 7378 return Top::Throw(Heap::illegal_argument_symbol()); 7379 } 7380 7381 // Get the number of steps. 7382 int step_count = NumberToInt32(args[2]); 7383 if (step_count < 1) { 7384 return Top::Throw(Heap::illegal_argument_symbol()); 7385 } 7386 7387 // Clear all current stepping setup. 7388 Debug::ClearStepping(); 7389 7390 // Prepare step. 7391 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count); 7392 return Heap::undefined_value(); 7393} 7394 7395 7396// Clear all stepping set by PrepareStep. 7397static Object* Runtime_ClearStepping(Arguments args) { 7398 HandleScope scope; 7399 ASSERT(args.length() == 0); 7400 Debug::ClearStepping(); 7401 return Heap::undefined_value(); 7402} 7403 7404 7405// Creates a copy of the with context chain. The copy of the context chain is 7406// is linked to the function context supplied. 7407static Handle<Context> CopyWithContextChain(Handle<Context> context_chain, 7408 Handle<Context> function_context) { 7409 // At the bottom of the chain. Return the function context to link to. 7410 if (context_chain->is_function_context()) { 7411 return function_context; 7412 } 7413 7414 // Recursively copy the with contexts. 7415 Handle<Context> previous(context_chain->previous()); 7416 Handle<JSObject> extension(JSObject::cast(context_chain->extension())); 7417 return Factory::NewWithContext( 7418 CopyWithContextChain(function_context, previous), 7419 extension, 7420 context_chain->IsCatchContext()); 7421} 7422 7423 7424// Helper function to find or create the arguments object for 7425// Runtime_DebugEvaluate. 7426static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame, 7427 Handle<JSFunction> function, 7428 Handle<Code> code, 7429 const ScopeInfo<>* sinfo, 7430 Handle<Context> function_context) { 7431 // Try to find the value of 'arguments' to pass as parameter. If it is not 7432 // found (that is the debugged function does not reference 'arguments' and 7433 // does not support eval) then create an 'arguments' object. 7434 int index; 7435 if (sinfo->number_of_stack_slots() > 0) { 7436 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol()); 7437 if (index != -1) { 7438 return Handle<Object>(frame->GetExpression(index)); 7439 } 7440 } 7441 7442 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) { 7443 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(), 7444 NULL); 7445 if (index != -1) { 7446 return Handle<Object>(function_context->get(index)); 7447 } 7448 } 7449 7450 const int length = frame->GetProvidedParametersCount(); 7451 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length); 7452 Handle<FixedArray> array = Factory::NewFixedArray(length); 7453 WriteBarrierMode mode = array->GetWriteBarrierMode(); 7454 for (int i = 0; i < length; i++) { 7455 array->set(i, frame->GetParameter(i), mode); 7456 } 7457 arguments->set_elements(*array); 7458 return arguments; 7459} 7460 7461 7462// Evaluate a piece of JavaScript in the context of a stack frame for 7463// debugging. This is accomplished by creating a new context which in its 7464// extension part has all the parameters and locals of the function on the 7465// stack frame. A function which calls eval with the code to evaluate is then 7466// compiled in this context and called in this context. As this context 7467// replaces the context of the function on the stack frame a new (empty) 7468// function is created as well to be used as the closure for the context. 7469// This function and the context acts as replacements for the function on the 7470// stack frame presenting the same view of the values of parameters and 7471// local variables as if the piece of JavaScript was evaluated at the point 7472// where the function on the stack frame is currently stopped. 7473static Object* Runtime_DebugEvaluate(Arguments args) { 7474 HandleScope scope; 7475 7476 // Check the execution state and decode arguments frame and source to be 7477 // evaluated. 7478 ASSERT(args.length() == 4); 7479 Object* check_result = Runtime_CheckExecutionState(args); 7480 if (check_result->IsFailure()) return check_result; 7481 CONVERT_CHECKED(Smi, wrapped_id, args[1]); 7482 CONVERT_ARG_CHECKED(String, source, 2); 7483 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]); 7484 7485 // Handle the processing of break. 7486 DisableBreak disable_break_save(disable_break); 7487 7488 // Get the frame where the debugging is performed. 7489 StackFrame::Id id = UnwrapFrameId(wrapped_id); 7490 JavaScriptFrameIterator it(id); 7491 JavaScriptFrame* frame = it.frame(); 7492 Handle<JSFunction> function(JSFunction::cast(frame->function())); 7493 Handle<Code> code(function->code()); 7494 ScopeInfo<> sinfo(*code); 7495 7496 // Traverse the saved contexts chain to find the active context for the 7497 // selected frame. 7498 SaveContext* save = Top::save_context(); 7499 while (save != NULL && !save->below(frame)) { 7500 save = save->prev(); 7501 } 7502 ASSERT(save != NULL); 7503 SaveContext savex; 7504 Top::set_context(*(save->context())); 7505 7506 // Create the (empty) function replacing the function on the stack frame for 7507 // the purpose of evaluating in the context created below. It is important 7508 // that this function does not describe any parameters and local variables 7509 // in the context. If it does then this will cause problems with the lookup 7510 // in Context::Lookup, where context slots for parameters and local variables 7511 // are looked at before the extension object. 7512 Handle<JSFunction> go_between = 7513 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value()); 7514 go_between->set_context(function->context()); 7515#ifdef DEBUG 7516 ScopeInfo<> go_between_sinfo(go_between->shared()->code()); 7517 ASSERT(go_between_sinfo.number_of_parameters() == 0); 7518 ASSERT(go_between_sinfo.number_of_context_slots() == 0); 7519#endif 7520 7521 // Materialize the content of the local scope into a JSObject. 7522 Handle<JSObject> local_scope = MaterializeLocalScope(frame); 7523 7524 // Allocate a new context for the debug evaluation and set the extension 7525 // object build. 7526 Handle<Context> context = 7527 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between); 7528 context->set_extension(*local_scope); 7529 // Copy any with contexts present and chain them in front of this context. 7530 Handle<Context> frame_context(Context::cast(frame->context())); 7531 Handle<Context> function_context(frame_context->fcontext()); 7532 context = CopyWithContextChain(frame_context, context); 7533 7534 // Wrap the evaluation statement in a new function compiled in the newly 7535 // created context. The function has one parameter which has to be called 7536 // 'arguments'. This it to have access to what would have been 'arguments' in 7537 // the function being debugged. 7538 // function(arguments,__source__) {return eval(__source__);} 7539 static const char* source_str = 7540 "(function(arguments,__source__){return eval(__source__);})"; 7541 static const int source_str_length = StrLength(source_str); 7542 Handle<String> function_source = 7543 Factory::NewStringFromAscii(Vector<const char>(source_str, 7544 source_str_length)); 7545 Handle<JSFunction> boilerplate = 7546 Compiler::CompileEval(function_source, 7547 context, 7548 context->IsGlobalContext(), 7549 Compiler::DONT_VALIDATE_JSON); 7550 if (boilerplate.is_null()) return Failure::Exception(); 7551 Handle<JSFunction> compiled_function = 7552 Factory::NewFunctionFromBoilerplate(boilerplate, context); 7553 7554 // Invoke the result of the compilation to get the evaluation function. 7555 bool has_pending_exception; 7556 Handle<Object> receiver(frame->receiver()); 7557 Handle<Object> evaluation_function = 7558 Execution::Call(compiled_function, receiver, 0, NULL, 7559 &has_pending_exception); 7560 if (has_pending_exception) return Failure::Exception(); 7561 7562 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo, 7563 function_context); 7564 7565 // Invoke the evaluation function and return the result. 7566 const int argc = 2; 7567 Object** argv[argc] = { arguments.location(), 7568 Handle<Object>::cast(source).location() }; 7569 Handle<Object> result = 7570 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver, 7571 argc, argv, &has_pending_exception); 7572 if (has_pending_exception) return Failure::Exception(); 7573 7574 // Skip the global proxy as it has no properties and always delegates to the 7575 // real global object. 7576 if (result->IsJSGlobalProxy()) { 7577 result = Handle<JSObject>(JSObject::cast(result->GetPrototype())); 7578 } 7579 7580 return *result; 7581} 7582 7583 7584static Object* Runtime_DebugEvaluateGlobal(Arguments args) { 7585 HandleScope scope; 7586 7587 // Check the execution state and decode arguments frame and source to be 7588 // evaluated. 7589 ASSERT(args.length() == 3); 7590 Object* check_result = Runtime_CheckExecutionState(args); 7591 if (check_result->IsFailure()) return check_result; 7592 CONVERT_ARG_CHECKED(String, source, 1); 7593 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]); 7594 7595 // Handle the processing of break. 7596 DisableBreak disable_break_save(disable_break); 7597 7598 // Enter the top context from before the debugger was invoked. 7599 SaveContext save; 7600 SaveContext* top = &save; 7601 while (top != NULL && *top->context() == *Debug::debug_context()) { 7602 top = top->prev(); 7603 } 7604 if (top != NULL) { 7605 Top::set_context(*top->context()); 7606 } 7607 7608 // Get the global context now set to the top context from before the 7609 // debugger was invoked. 7610 Handle<Context> context = Top::global_context(); 7611 7612 // Compile the source to be evaluated. 7613 Handle<JSFunction> boilerplate = 7614 Handle<JSFunction>(Compiler::CompileEval(source, 7615 context, 7616 true, 7617 Compiler::DONT_VALIDATE_JSON)); 7618 if (boilerplate.is_null()) return Failure::Exception(); 7619 Handle<JSFunction> compiled_function = 7620 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate, 7621 context)); 7622 7623 // Invoke the result of the compilation to get the evaluation function. 7624 bool has_pending_exception; 7625 Handle<Object> receiver = Top::global(); 7626 Handle<Object> result = 7627 Execution::Call(compiled_function, receiver, 0, NULL, 7628 &has_pending_exception); 7629 if (has_pending_exception) return Failure::Exception(); 7630 return *result; 7631} 7632 7633 7634static Object* Runtime_DebugGetLoadedScripts(Arguments args) { 7635 HandleScope scope; 7636 ASSERT(args.length() == 0); 7637 7638 // Fill the script objects. 7639 Handle<FixedArray> instances = Debug::GetLoadedScripts(); 7640 7641 // Convert the script objects to proper JS objects. 7642 for (int i = 0; i < instances->length(); i++) { 7643 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); 7644 // Get the script wrapper in a local handle before calling GetScriptWrapper, 7645 // because using 7646 // instances->set(i, *GetScriptWrapper(script)) 7647 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might 7648 // already have deferenced the instances handle. 7649 Handle<JSValue> wrapper = GetScriptWrapper(script); 7650 instances->set(i, *wrapper); 7651 } 7652 7653 // Return result as a JS array. 7654 Handle<JSObject> result = Factory::NewJSObject(Top::array_function()); 7655 Handle<JSArray>::cast(result)->SetContent(*instances); 7656 return *result; 7657} 7658 7659 7660// Helper function used by Runtime_DebugReferencedBy below. 7661static int DebugReferencedBy(JSObject* target, 7662 Object* instance_filter, int max_references, 7663 FixedArray* instances, int instances_size, 7664 JSFunction* arguments_function) { 7665 NoHandleAllocation ha; 7666 AssertNoAllocation no_alloc; 7667 7668 // Iterate the heap. 7669 int count = 0; 7670 JSObject* last = NULL; 7671 HeapIterator iterator; 7672 HeapObject* heap_obj = NULL; 7673 while (((heap_obj = iterator.next()) != NULL) && 7674 (max_references == 0 || count < max_references)) { 7675 // Only look at all JSObjects. 7676 if (heap_obj->IsJSObject()) { 7677 // Skip context extension objects and argument arrays as these are 7678 // checked in the context of functions using them. 7679 JSObject* obj = JSObject::cast(heap_obj); 7680 if (obj->IsJSContextExtensionObject() || 7681 obj->map()->constructor() == arguments_function) { 7682 continue; 7683 } 7684 7685 // Check if the JS object has a reference to the object looked for. 7686 if (obj->ReferencesObject(target)) { 7687 // Check instance filter if supplied. This is normally used to avoid 7688 // references from mirror objects (see Runtime_IsInPrototypeChain). 7689 if (!instance_filter->IsUndefined()) { 7690 Object* V = obj; 7691 while (true) { 7692 Object* prototype = V->GetPrototype(); 7693 if (prototype->IsNull()) { 7694 break; 7695 } 7696 if (instance_filter == prototype) { 7697 obj = NULL; // Don't add this object. 7698 break; 7699 } 7700 V = prototype; 7701 } 7702 } 7703 7704 if (obj != NULL) { 7705 // Valid reference found add to instance array if supplied an update 7706 // count. 7707 if (instances != NULL && count < instances_size) { 7708 instances->set(count, obj); 7709 } 7710 last = obj; 7711 count++; 7712 } 7713 } 7714 } 7715 } 7716 7717 // Check for circular reference only. This can happen when the object is only 7718 // referenced from mirrors and has a circular reference in which case the 7719 // object is not really alive and would have been garbage collected if not 7720 // referenced from the mirror. 7721 if (count == 1 && last == target) { 7722 count = 0; 7723 } 7724 7725 // Return the number of referencing objects found. 7726 return count; 7727} 7728 7729 7730// Scan the heap for objects with direct references to an object 7731// args[0]: the object to find references to 7732// args[1]: constructor function for instances to exclude (Mirror) 7733// args[2]: the the maximum number of objects to return 7734static Object* Runtime_DebugReferencedBy(Arguments args) { 7735 ASSERT(args.length() == 3); 7736 7737 // First perform a full GC in order to avoid references from dead objects. 7738 Heap::CollectAllGarbage(false); 7739 7740 // Check parameters. 7741 CONVERT_CHECKED(JSObject, target, args[0]); 7742 Object* instance_filter = args[1]; 7743 RUNTIME_ASSERT(instance_filter->IsUndefined() || 7744 instance_filter->IsJSObject()); 7745 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); 7746 RUNTIME_ASSERT(max_references >= 0); 7747 7748 // Get the constructor function for context extension and arguments array. 7749 JSObject* arguments_boilerplate = 7750 Top::context()->global_context()->arguments_boilerplate(); 7751 JSFunction* arguments_function = 7752 JSFunction::cast(arguments_boilerplate->map()->constructor()); 7753 7754 // Get the number of referencing objects. 7755 int count; 7756 count = DebugReferencedBy(target, instance_filter, max_references, 7757 NULL, 0, arguments_function); 7758 7759 // Allocate an array to hold the result. 7760 Object* object = Heap::AllocateFixedArray(count); 7761 if (object->IsFailure()) return object; 7762 FixedArray* instances = FixedArray::cast(object); 7763 7764 // Fill the referencing objects. 7765 count = DebugReferencedBy(target, instance_filter, max_references, 7766 instances, count, arguments_function); 7767 7768 // Return result as JS array. 7769 Object* result = 7770 Heap::AllocateJSObject( 7771 Top::context()->global_context()->array_function()); 7772 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances); 7773 return result; 7774} 7775 7776 7777// Helper function used by Runtime_DebugConstructedBy below. 7778static int DebugConstructedBy(JSFunction* constructor, int max_references, 7779 FixedArray* instances, int instances_size) { 7780 AssertNoAllocation no_alloc; 7781 7782 // Iterate the heap. 7783 int count = 0; 7784 HeapIterator iterator; 7785 HeapObject* heap_obj = NULL; 7786 while (((heap_obj = iterator.next()) != NULL) && 7787 (max_references == 0 || count < max_references)) { 7788 // Only look at all JSObjects. 7789 if (heap_obj->IsJSObject()) { 7790 JSObject* obj = JSObject::cast(heap_obj); 7791 if (obj->map()->constructor() == constructor) { 7792 // Valid reference found add to instance array if supplied an update 7793 // count. 7794 if (instances != NULL && count < instances_size) { 7795 instances->set(count, obj); 7796 } 7797 count++; 7798 } 7799 } 7800 } 7801 7802 // Return the number of referencing objects found. 7803 return count; 7804} 7805 7806 7807// Scan the heap for objects constructed by a specific function. 7808// args[0]: the constructor to find instances of 7809// args[1]: the the maximum number of objects to return 7810static Object* Runtime_DebugConstructedBy(Arguments args) { 7811 ASSERT(args.length() == 2); 7812 7813 // First perform a full GC in order to avoid dead objects. 7814 Heap::CollectAllGarbage(false); 7815 7816 // Check parameters. 7817 CONVERT_CHECKED(JSFunction, constructor, args[0]); 7818 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); 7819 RUNTIME_ASSERT(max_references >= 0); 7820 7821 // Get the number of referencing objects. 7822 int count; 7823 count = DebugConstructedBy(constructor, max_references, NULL, 0); 7824 7825 // Allocate an array to hold the result. 7826 Object* object = Heap::AllocateFixedArray(count); 7827 if (object->IsFailure()) return object; 7828 FixedArray* instances = FixedArray::cast(object); 7829 7830 // Fill the referencing objects. 7831 count = DebugConstructedBy(constructor, max_references, instances, count); 7832 7833 // Return result as JS array. 7834 Object* result = 7835 Heap::AllocateJSObject( 7836 Top::context()->global_context()->array_function()); 7837 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances); 7838 return result; 7839} 7840 7841 7842// Find the effective prototype object as returned by __proto__. 7843// args[0]: the object to find the prototype for. 7844static Object* Runtime_DebugGetPrototype(Arguments args) { 7845 ASSERT(args.length() == 1); 7846 7847 CONVERT_CHECKED(JSObject, obj, args[0]); 7848 7849 // Use the __proto__ accessor. 7850 return Accessors::ObjectPrototype.getter(obj, NULL); 7851} 7852 7853 7854static Object* Runtime_SystemBreak(Arguments args) { 7855 ASSERT(args.length() == 0); 7856 CPU::DebugBreak(); 7857 return Heap::undefined_value(); 7858} 7859 7860 7861static Object* Runtime_DebugDisassembleFunction(Arguments args) { 7862#ifdef DEBUG 7863 HandleScope scope; 7864 ASSERT(args.length() == 1); 7865 // Get the function and make sure it is compiled. 7866 CONVERT_ARG_CHECKED(JSFunction, func, 0); 7867 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) { 7868 return Failure::Exception(); 7869 } 7870 func->code()->PrintLn(); 7871#endif // DEBUG 7872 return Heap::undefined_value(); 7873} 7874 7875 7876static Object* Runtime_DebugDisassembleConstructor(Arguments args) { 7877#ifdef DEBUG 7878 HandleScope scope; 7879 ASSERT(args.length() == 1); 7880 // Get the function and make sure it is compiled. 7881 CONVERT_ARG_CHECKED(JSFunction, func, 0); 7882 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) { 7883 return Failure::Exception(); 7884 } 7885 func->shared()->construct_stub()->PrintLn(); 7886#endif // DEBUG 7887 return Heap::undefined_value(); 7888} 7889 7890 7891static Object* Runtime_FunctionGetInferredName(Arguments args) { 7892 NoHandleAllocation ha; 7893 ASSERT(args.length() == 1); 7894 7895 CONVERT_CHECKED(JSFunction, f, args[0]); 7896 return f->shared()->inferred_name(); 7897} 7898 7899#endif // ENABLE_DEBUGGER_SUPPORT 7900 7901#ifdef ENABLE_LOGGING_AND_PROFILING 7902 7903static Object* Runtime_ProfilerResume(Arguments args) { 7904 NoHandleAllocation ha; 7905 ASSERT(args.length() == 1); 7906 7907 CONVERT_CHECKED(Smi, smi_modules, args[0]); 7908 v8::V8::ResumeProfilerEx(smi_modules->value()); 7909 return Heap::undefined_value(); 7910} 7911 7912 7913static Object* Runtime_ProfilerPause(Arguments args) { 7914 NoHandleAllocation ha; 7915 ASSERT(args.length() == 1); 7916 7917 CONVERT_CHECKED(Smi, smi_modules, args[0]); 7918 v8::V8::PauseProfilerEx(smi_modules->value()); 7919 return Heap::undefined_value(); 7920} 7921 7922#endif // ENABLE_LOGGING_AND_PROFILING 7923 7924// Finds the script object from the script data. NOTE: This operation uses 7925// heap traversal to find the function generated for the source position 7926// for the requested break point. For lazily compiled functions several heap 7927// traversals might be required rendering this operation as a rather slow 7928// operation. However for setting break points which is normally done through 7929// some kind of user interaction the performance is not crucial. 7930static Handle<Object> Runtime_GetScriptFromScriptName( 7931 Handle<String> script_name) { 7932 // Scan the heap for Script objects to find the script with the requested 7933 // script data. 7934 Handle<Script> script; 7935 HeapIterator iterator; 7936 HeapObject* obj = NULL; 7937 while (script.is_null() && ((obj = iterator.next()) != NULL)) { 7938 // If a script is found check if it has the script data requested. 7939 if (obj->IsScript()) { 7940 if (Script::cast(obj)->name()->IsString()) { 7941 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { 7942 script = Handle<Script>(Script::cast(obj)); 7943 } 7944 } 7945 } 7946 } 7947 7948 // If no script with the requested script data is found return undefined. 7949 if (script.is_null()) return Factory::undefined_value(); 7950 7951 // Return the script found. 7952 return GetScriptWrapper(script); 7953} 7954 7955 7956// Get the script object from script data. NOTE: Regarding performance 7957// see the NOTE for GetScriptFromScriptData. 7958// args[0]: script data for the script to find the source for 7959static Object* Runtime_GetScript(Arguments args) { 7960 HandleScope scope; 7961 7962 ASSERT(args.length() == 1); 7963 7964 CONVERT_CHECKED(String, script_name, args[0]); 7965 7966 // Find the requested script. 7967 Handle<Object> result = 7968 Runtime_GetScriptFromScriptName(Handle<String>(script_name)); 7969 return *result; 7970} 7971 7972 7973// Determines whether the given stack frame should be displayed in 7974// a stack trace. The caller is the error constructor that asked 7975// for the stack trace to be collected. The first time a construct 7976// call to this function is encountered it is skipped. The seen_caller 7977// in/out parameter is used to remember if the caller has been seen 7978// yet. 7979static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller, 7980 bool* seen_caller) { 7981 // Only display JS frames. 7982 if (!raw_frame->is_java_script()) 7983 return false; 7984 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); 7985 Object* raw_fun = frame->function(); 7986 // Not sure when this can happen but skip it just in case. 7987 if (!raw_fun->IsJSFunction()) 7988 return false; 7989 if ((raw_fun == caller) && !(*seen_caller)) { 7990 *seen_caller = true; 7991 return false; 7992 } 7993 // Skip all frames until we've seen the caller. Also, skip the most 7994 // obvious builtin calls. Some builtin calls (such as Number.ADD 7995 // which is invoked using 'call') are very difficult to recognize 7996 // so we're leaving them in for now. 7997 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject(); 7998} 7999 8000 8001// Collect the raw data for a stack trace. Returns an array of three 8002// element segments each containing a receiver, function and native 8003// code offset. 8004static Object* Runtime_CollectStackTrace(Arguments args) { 8005 ASSERT_EQ(args.length(), 2); 8006 Handle<Object> caller = args.at<Object>(0); 8007 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]); 8008 8009 HandleScope scope; 8010 8011 limit = Max(limit, 0); // Ensure that limit is not negative. 8012 int initial_size = Min(limit, 10); 8013 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3); 8014 8015 StackFrameIterator iter; 8016 // If the caller parameter is a function we skip frames until we're 8017 // under it before starting to collect. 8018 bool seen_caller = !caller->IsJSFunction(); 8019 int cursor = 0; 8020 int frames_seen = 0; 8021 while (!iter.done() && frames_seen < limit) { 8022 StackFrame* raw_frame = iter.frame(); 8023 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) { 8024 frames_seen++; 8025 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); 8026 Object* recv = frame->receiver(); 8027 Object* fun = frame->function(); 8028 Address pc = frame->pc(); 8029 Address start = frame->code()->address(); 8030 Smi* offset = Smi::FromInt(static_cast<int>(pc - start)); 8031 FixedArray* elements = FixedArray::cast(result->elements()); 8032 if (cursor + 2 < elements->length()) { 8033 elements->set(cursor++, recv); 8034 elements->set(cursor++, fun); 8035 elements->set(cursor++, offset, SKIP_WRITE_BARRIER); 8036 } else { 8037 HandleScope scope; 8038 Handle<Object> recv_handle(recv); 8039 Handle<Object> fun_handle(fun); 8040 SetElement(result, cursor++, recv_handle); 8041 SetElement(result, cursor++, fun_handle); 8042 SetElement(result, cursor++, Handle<Smi>(offset)); 8043 } 8044 } 8045 iter.Advance(); 8046 } 8047 8048 result->set_length(Smi::FromInt(cursor), SKIP_WRITE_BARRIER); 8049 8050 return *result; 8051} 8052 8053 8054// Returns V8 version as a string. 8055static Object* Runtime_GetV8Version(Arguments args) { 8056 ASSERT_EQ(args.length(), 0); 8057 8058 NoHandleAllocation ha; 8059 8060 const char* version_string = v8::V8::GetVersion(); 8061 8062 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED); 8063} 8064 8065 8066static Object* Runtime_Abort(Arguments args) { 8067 ASSERT(args.length() == 2); 8068 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) + 8069 Smi::cast(args[1])->value()); 8070 Top::PrintStack(); 8071 OS::Abort(); 8072 UNREACHABLE(); 8073 return NULL; 8074} 8075 8076 8077static Object* Runtime_DeleteHandleScopeExtensions(Arguments args) { 8078 ASSERT(args.length() == 0); 8079 HandleScope::DeleteExtensions(); 8080 return Heap::undefined_value(); 8081} 8082 8083 8084#ifdef DEBUG 8085// ListNatives is ONLY used by the fuzz-natives.js in debug mode 8086// Exclude the code in release mode. 8087static Object* Runtime_ListNatives(Arguments args) { 8088 ASSERT(args.length() == 0); 8089 HandleScope scope; 8090 Handle<JSArray> result = Factory::NewJSArray(0); 8091 int index = 0; 8092#define ADD_ENTRY(Name, argc, ressize) \ 8093 { \ 8094 HandleScope inner; \ 8095 Handle<String> name = \ 8096 Factory::NewStringFromAscii( \ 8097 Vector<const char>(#Name, StrLength(#Name))); \ 8098 Handle<JSArray> pair = Factory::NewJSArray(0); \ 8099 SetElement(pair, 0, name); \ 8100 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \ 8101 SetElement(result, index++, pair); \ 8102 } 8103 RUNTIME_FUNCTION_LIST(ADD_ENTRY) 8104#undef ADD_ENTRY 8105 return *result; 8106} 8107#endif 8108 8109 8110static Object* Runtime_Log(Arguments args) { 8111 ASSERT(args.length() == 2); 8112 CONVERT_CHECKED(String, format, args[0]); 8113 CONVERT_CHECKED(JSArray, elms, args[1]); 8114 Vector<const char> chars = format->ToAsciiVector(); 8115 Logger::LogRuntime(chars, elms); 8116 return Heap::undefined_value(); 8117} 8118 8119 8120static Object* Runtime_IS_VAR(Arguments args) { 8121 UNREACHABLE(); // implemented as macro in the parser 8122 return NULL; 8123} 8124 8125 8126// ---------------------------------------------------------------------------- 8127// Implementation of Runtime 8128 8129#define F(name, nargs, ressize) \ 8130 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \ 8131 static_cast<int>(Runtime::k##name), ressize }, 8132 8133static Runtime::Function Runtime_functions[] = { 8134 RUNTIME_FUNCTION_LIST(F) 8135 { NULL, NULL, NULL, 0, -1, 0 } 8136}; 8137 8138#undef F 8139 8140 8141Runtime::Function* Runtime::FunctionForId(FunctionId fid) { 8142 ASSERT(0 <= fid && fid < kNofFunctions); 8143 return &Runtime_functions[fid]; 8144} 8145 8146 8147Runtime::Function* Runtime::FunctionForName(const char* name) { 8148 for (Function* f = Runtime_functions; f->name != NULL; f++) { 8149 if (strcmp(f->name, name) == 0) { 8150 return f; 8151 } 8152 } 8153 return NULL; 8154} 8155 8156 8157void Runtime::PerformGC(Object* result) { 8158 Failure* failure = Failure::cast(result); 8159 if (failure->IsRetryAfterGC()) { 8160 // Try to do a garbage collection; ignore it if it fails. The C 8161 // entry stub will throw an out-of-memory exception in that case. 8162 Heap::CollectGarbage(failure->requested(), failure->allocation_space()); 8163 } else { 8164 // Handle last resort GC and make sure to allow future allocations 8165 // to grow the heap without causing GCs (if possible). 8166 Counters::gc_last_resort_from_js.Increment(); 8167 Heap::CollectAllGarbage(false); 8168 } 8169} 8170 8171 8172} } // namespace v8::internal 8173