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