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