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