blob: 4d53cebdad20789651ee3bb3150c9e81c7126f03 [file] [log] [blame]
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001// Copyright 2006-2008 Google Inc. 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 "debug.h"
39#include "execution.h"
40#include "jsregexp.h"
41#include "platform.h"
42#include "runtime.h"
43#include "scopeinfo.h"
44#include "v8threads.h"
45
46namespace v8 { namespace internal {
47
48
49#define RUNTIME_ASSERT(value) do { \
50 if (!(value)) return IllegalOperation(); \
51} while (false)
52
53// Cast the given object to a value of the specified type and store
54// it in a variable with the given name. If the object is not of the
55// expected type call IllegalOperation and return.
56#define CONVERT_CHECKED(Type, name, obj) \
57 RUNTIME_ASSERT(obj->Is##Type()); \
58 Type* name = Type::cast(obj);
59
60#define CONVERT_ARG_CHECKED(Type, name, index) \
61 RUNTIME_ASSERT(args[index]->Is##Type()); \
62 Handle<Type> name = args.at<Type>(index);
63
kasper.lundbd3ec4e2008-07-09 11:06:54 +000064// Cast the given object to a boolean and store it in a variable with
65// the given name. If the object is not a boolean call IllegalOperation
66// and return.
67#define CONVERT_BOOLEAN_CHECKED(name, obj) \
68 RUNTIME_ASSERT(obj->IsBoolean()); \
69 bool name = (obj)->IsTrue();
70
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071// Cast the given object to a double and store it in a variable with
72// the given name. If the object is not a number (as opposed to
73// the number not-a-number) call IllegalOperation and return.
74#define CONVERT_DOUBLE_CHECKED(name, obj) \
75 RUNTIME_ASSERT(obj->IsNumber()); \
76 double name = (obj)->Number();
77
78// Call the specified converter on the object *comand store the result in
79// a variable of the specified type with the given name. If the
80// object is not a Number call IllegalOperation and return.
81#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
82 RUNTIME_ASSERT(obj->IsNumber()); \
83 type name = NumberTo##Type(obj);
84
85// Non-reentrant string buffer for efficient general use in this file.
86static StaticResource<StringInputBuffer> string_input_buffer;
87
88
89static Object* IllegalOperation() {
90 return Top::Throw(Heap::illegal_access_symbol());
91}
92
93
94static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
95 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
96
97#ifdef DEBUG
98 // Verify the constructor of the boilerplate is equal to the
99 // object function in the CURRENT global_context.
100 CHECK(boilerplate->map()->constructor()
101 == Top::context()->global_context()->object_function());
102#endif
103 return boilerplate->Copy();
104}
105
106
107static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
108 HandleScope scope;
109 ASSERT(args.length() == 3);
110 // Copy the arguments.
111 Handle<FixedArray> literals = args.at<FixedArray>(0);
112 int literals_index = Smi::cast(args[1])->value();
113 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
114
115 // Create the boilerplate object for the function literal
116 Handle<JSObject> boilerplate =
117 Factory::NewJSObject(Top::object_function(), TENURED);
118
119 { // Add the constant propeties to the boilerplate.
120 int length = constant_properties->length();
121 OptimizedObjectForAddingMultipleProperties opt(boilerplate, true);
122 for (int index = 0; index < length; index +=2) {
123 Handle<Object> key(constant_properties->get(index+0));
124 Handle<Object> value(constant_properties->get(index+1));
125 uint32_t element_index = 0;
126 if (key->IsSymbol()) {
127 // If key is a symbol it is not an array element.
128 Handle<String> name(String::cast(*key));
129 ASSERT(!name->AsArrayIndex(&element_index));
130 SetProperty(boilerplate, name, value, NONE);
131 } else if (Array::IndexFromObject(*key, &element_index)) {
132 // Array index (uint32).
133 SetElement(boilerplate, element_index, value);
134 } else {
135 // Non-uint32 number.
136 ASSERT(key->IsNumber());
137 double num = key->Number();
138 char arr[100];
139 Vector<char> buffer(arr, ARRAY_SIZE(arr));
140 const char* str = DoubleToCString(num, buffer);
141 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
142 SetProperty(boilerplate, name, value, NONE);
143 }
144 }
145 }
146
147 // Update the functions literal and return the boilerplate.
148 literals->set(literals_index, *boilerplate);
149
150 return *boilerplate;
151}
152
153
154static Object* Runtime_CreateArrayLiteral(Arguments args) {
155 // Takes a FixedArray containing literals and produces
156 // JSArray with the elements matching the literals.
157 ASSERT(args.length() == 1);
158 CONVERT_CHECKED(FixedArray, literals, args[0]);
159
160 // Retrieve the array constructor from the global context.
161 JSFunction* constructor =
162 JSFunction::cast(Top::context()->global_context()->array_function());
163
164 // Create the JSArray.
165 Object* object = Heap::AllocateJSObject(constructor);
166 if (object->IsFailure()) return object;
167
168 // Copy the literals.
169 Object* elements = literals->Copy();
170 if (elements->IsFailure()) return elements;
171
172 // Set the elements.
173 JSArray::cast(object)->SetContent(FixedArray::cast(elements));
174 return object;
175}
176
177
178static Object* Runtime_ClassOf(Arguments args) {
179 NoHandleAllocation ha;
180 ASSERT(args.length() == 1);
181 Object* obj = args[0];
182 if (!obj->IsJSObject()) return Heap::null_value();
183 return JSObject::cast(obj)->class_name();
184}
185
186
187static Object* Runtime_IsInPrototypeChain(Arguments args) {
188 NoHandleAllocation ha;
189 ASSERT(args.length() == 2);
190 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
191 Object* O = args[0];
192 Object* V = args[1];
193 while (true) {
194 Object* prototype = V->GetPrototype();
195 if (prototype->IsNull()) return Heap::false_value();
196 if (O == prototype) return Heap::true_value();
197 V = prototype;
198 }
199}
200
201
202static Object* Runtime_IsConstructCall(Arguments args) {
203 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000204 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000205 JavaScriptFrameIterator it;
206 return Heap::ToBoolean(it.frame()->IsConstructor());
207}
208
209
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210static Object* Runtime_RegExpCompile(Arguments args) {
211 HandleScope scope; // create a new handle scope
212 ASSERT(args.length() == 3);
213 CONVERT_CHECKED(JSValue, raw_re, args[0]);
214 Handle<JSValue> re(raw_re);
215 CONVERT_CHECKED(String, raw_pattern, args[1]);
216 Handle<String> pattern(raw_pattern);
217 CONVERT_CHECKED(String, raw_flags, args[2]);
218 Handle<String> flags(raw_flags);
219 return *RegExpImpl::JsreCompile(re, pattern, flags);
220}
221
222
223static Object* Runtime_CreateApiFunction(Arguments args) {
224 HandleScope scope;
225 ASSERT(args.length() == 1);
226 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
227 Handle<FunctionTemplateInfo> data(raw_data);
228 return *Factory::CreateApiFunction(data);
229}
230
231
232static Object* Runtime_IsTemplate(Arguments args) {
233 ASSERT(args.length() == 1);
234 Object* arg = args[0];
235 bool result = arg->IsObjectTemplateInfo()
236 || arg->IsFunctionTemplateInfo();
237 return Heap::ToBoolean(result);
238}
239
240
241static Object* Runtime_GetTemplateField(Arguments args) {
242 ASSERT(args.length() == 2);
243 CONVERT_CHECKED(HeapObject, templ, args[0]);
244 RUNTIME_ASSERT(templ->IsStruct());
245 CONVERT_CHECKED(Smi, field, args[1]);
246 return HeapObject::GetHeapObjectField(templ, field->value());
247}
248
249
250static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
251 HandleScope scope;
252 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
253 Handle<Object> args[2] = { type_handle, name };
254 Handle<Object> error =
255 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
256 return Top::Throw(*error);
257}
258
259
260static Object* Runtime_DeclareGlobals(Arguments args) {
261 HandleScope scope;
262 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
263
264 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
265 Handle<Context> context = args.at<Context>(1);
266 bool is_eval = Smi::cast(args[2])->value() == 1;
267
268 // Compute the property attributes. According to ECMA-262, section
269 // 13, page 71, the property must be read-only and
270 // non-deletable. However, neither SpiderMonkey nor KJS creates the
271 // property as read-only, so we don't either.
272 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
273
274 // Only optimize the object if we intend to add more than 5 properties.
275 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
276
277 // Traverse the name/value pairs and set the properties.
278 int length = pairs->length();
279 for (int i = 0; i < length; i += 2) {
280 HandleScope scope;
281 Handle<String> name(String::cast(pairs->get(i)));
282 Handle<Object> value(pairs->get(i + 1));
283
284 // We have to declare a global const property. To capture we only
285 // assign to it when evaluating the assignment for "const x =
286 // <expr>" the initial value is the hole.
287 bool is_const_property = value->IsTheHole();
288
289 if (value->IsUndefined() || is_const_property) {
290 // Lookup the property in the global object, and don't set the
291 // value of the variable if the property is already there.
292 LookupResult lookup;
293 global->Lookup(*name, &lookup);
294 if (lookup.IsProperty()) {
295 // Determine if the property is local by comparing the holder
296 // against the global object. The information will be used to
297 // avoid throwing re-declaration errors when declaring
298 // variables or constants that exist in the prototype chain.
299 bool is_local = (*global == lookup.holder());
300 // Get the property attributes and determine if the property is
301 // read-only.
302 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
303 bool is_read_only = (attributes & READ_ONLY) != 0;
304 if (lookup.type() == INTERCEPTOR) {
305 // If the interceptor says the property is there, we
306 // just return undefined without overwriting the property.
307 // Otherwise, we continue to setting the property.
308 if (attributes != ABSENT) {
309 // Check if the existing property conflicts with regards to const.
310 if (is_local && (is_read_only || is_const_property)) {
311 const char* type = (is_read_only) ? "const" : "var";
312 return ThrowRedeclarationError(type, name);
313 };
314 // The property already exists without conflicting: Go to
315 // the next declaration.
316 continue;
317 }
318 // Fall-through and introduce the absent property by using
319 // SetProperty.
320 } else {
321 if (is_local && (is_read_only || is_const_property)) {
322 const char* type = (is_read_only) ? "const" : "var";
323 return ThrowRedeclarationError(type, name);
324 }
325 // The property already exists without conflicting: Go to
326 // the next declaration.
327 continue;
328 }
329 }
330 } else {
331 // Copy the function and update its context. Use it as value.
332 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
333 Handle<JSFunction> function =
334 Factory::NewFunctionFromBoilerplate(boilerplate, context);
335 value = function;
336 }
337
338 LookupResult lookup;
339 global->LocalLookup(*name, &lookup);
340
341 PropertyAttributes attributes = is_const_property
342 ? static_cast<PropertyAttributes>(base | READ_ONLY)
343 : base;
344
345 if (lookup.IsProperty()) {
346 // There's a local property that we need to overwrite because
347 // we're either declaring a function or there's an interceptor
348 // that claims the property is absent.
349
350 // Check for conflicting re-declarations. We cannot have
351 // conflicting types in case of intercepted properties because
352 // they are absent.
353 if (lookup.type() != INTERCEPTOR &&
354 (lookup.IsReadOnly() || is_const_property)) {
355 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
356 return ThrowRedeclarationError(type, name);
357 }
358 SetProperty(global, name, value, attributes);
359 } else {
360 // If a property with this name does not already exist on the
361 // global object add the property locally. We take special
362 // precautions to always add it as a local property even in case
363 // of callbacks in the prototype chain (this rules out using
364 // SetProperty). Also, we must use the handle-based version to
365 // avoid GC issues.
366 AddProperty(global, name, value, attributes);
367 }
368 }
369 // Done.
370 return Heap::undefined_value();
371}
372
373
374static Object* Runtime_DeclareContextSlot(Arguments args) {
375 HandleScope scope;
376 ASSERT(args.length() == 5);
377
378 // args[0] is result (TOS)
379 CONVERT_ARG_CHECKED(Context, context, 1);
380 Handle<String> name(String::cast(args[2]));
381 PropertyAttributes mode =
382 static_cast<PropertyAttributes>(Smi::cast(args[3])->value());
383 ASSERT(mode == READ_ONLY || mode == NONE);
384 Handle<Object> initial_value(args[4]);
385
386 // Declarations are always done in the function context.
387 context = Handle<Context>(context->fcontext());
388
389 int index;
390 PropertyAttributes attributes;
391 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
392 Handle<Object> context_obj =
393 context->Lookup(name, flags, &index, &attributes);
394
395 if (attributes != ABSENT) {
396 // The name was declared before; check for conflicting
397 // re-declarations: This is similar to the code in parser.cc in
398 // the AstBuildingParser::Declare function.
399 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
400 // Functions are not read-only.
401 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
402 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
403 return ThrowRedeclarationError(type, name);
404 }
405
406 // Initialize it if necessary.
407 if (*initial_value != NULL) {
408 if (index >= 0) {
409 // The variable or constant context slot should always be in
410 // the function context; not in any outer context nor in the
411 // arguments object.
412 ASSERT(context_obj.is_identical_to(context));
413 if (((attributes & READ_ONLY) == 0) ||
414 context->get(index)->IsTheHole()) {
415 context->set(index, *initial_value);
416 }
417 } else {
418 // Slow case: The property is not in the FixedArray part of the context.
419 Handle<JSObject> context_ext = Handle<JSObject>::cast(context_obj);
420 SetProperty(context_ext, name, initial_value, mode);
421 }
422 }
423 return args[0]; // return TOS
424 }
425
426 // The property is not in the function context. It needs to be "declared"
427 // in the function context's extension context, or in the global context.
428 Handle<JSObject> context_ext;
429 if (context->extension() != NULL) {
430 // The function context's extension context exists - use it.
431 context_ext = Handle<JSObject>(context->extension());
432 } else {
433 // The function context's extension context does not exists - allocate it.
434 context_ext = Factory::NewJSObject(Top::context_extension_function());
435 // And store it in the extension slot.
436 context->set_extension(*context_ext);
437 }
438 ASSERT(*context_ext != NULL);
439
440 // Declare the property by setting it to the initial value if provided,
441 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
442 // constant declarations).
443 ASSERT(!context_ext->HasLocalProperty(*name));
444 Handle<Object> value(Heap::undefined_value());
445 if (*initial_value != NULL) value = initial_value;
446 SetProperty(context_ext, name, value, mode);
447 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
448 return args[0]; // return TOS
449}
450
451
452static Object* Runtime_InitializeVarGlobal(Arguments args) {
453 NoHandleAllocation nha;
454
455 // Determine if we need to assign to the variable if it already
456 // exists (based on the number of arguments).
457 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
458 bool assign = args.length() == 2;
459
460 CONVERT_ARG_CHECKED(String, name, 0);
461 GlobalObject* global = Top::context()->global();
462
463 // According to ECMA-262, section 12.2, page 62, the property must
464 // not be deletable.
465 PropertyAttributes attributes = DONT_DELETE;
466
467 // Lookup the property locally in the global object. If it isn't
468 // there, we add the property and take special precautions to always
469 // add it as a local property even in case of callbacks in the
470 // prototype chain (this rules out using SetProperty).
471 LookupResult lookup;
472 global->LocalLookup(*name, &lookup);
473 if (!lookup.IsProperty()) {
474 Object* value = (assign) ? args[1] : Heap::undefined_value();
475 return global->AddProperty(*name, value, attributes);
476 }
477
478 // Determine if this is a redeclaration of something read-only.
479 if (lookup.IsReadOnly()) {
480 return ThrowRedeclarationError("const", name);
481 }
482
483 // Determine if this is a redeclaration of an intercepted read-only
484 // property and figure out if the property exists at all.
485 bool found = true;
486 PropertyType type = lookup.type();
487 if (type == INTERCEPTOR) {
488 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
489 if (intercepted == ABSENT) {
490 // The interceptor claims the property isn't there. We need to
491 // make sure to introduce it.
492 found = false;
493 } else if ((intercepted & READ_ONLY) != 0) {
494 // The property is present, but read-only. Since we're trying to
495 // overwrite it with a variable declaration we must throw a
496 // re-declaration error.
497 return ThrowRedeclarationError("const", name);
498 }
499 // Restore global object from context (in case of GC).
500 global = Top::context()->global();
501 }
502
503 if (found && !assign) {
504 // The global property is there and we're not assigning any value
505 // to it. Just return.
506 return Heap::undefined_value();
507 }
508
509 // Assign the value (or undefined) to the property.
510 Object* value = (assign) ? args[1] : Heap::undefined_value();
511 return global->SetProperty(&lookup, *name, value, attributes);
512}
513
514
515static Object* Runtime_InitializeConstGlobal(Arguments args) {
516 // All constants are declared with an initial value. The name
517 // of the constant is the first argument and the initial value
518 // is the second.
519 RUNTIME_ASSERT(args.length() == 2);
520 CONVERT_ARG_CHECKED(String, name, 0);
521 Handle<Object> value = args.at<Object>(1);
522
523 // Get the current global object from top.
524 GlobalObject* global = Top::context()->global();
525
526 // According to ECMA-262, section 12.2, page 62, the property must
527 // not be deletable. Since it's a const, it must be READ_ONLY too.
528 PropertyAttributes attributes =
529 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
530
531 // Lookup the property locally in the global object. If it isn't
532 // there, we add the property and take special precautions to always
533 // add it as a local property even in case of callbacks in the
534 // prototype chain (this rules out using SetProperty).
535 LookupResult lookup;
536 global->LocalLookup(*name, &lookup);
537 if (!lookup.IsProperty()) {
538 return global->AddProperty(*name, *value, attributes);
539 }
540
541 // Determine if this is a redeclaration of something not
542 // read-only. In case the result is hidden behind an interceptor we
543 // need to ask it for the property attributes.
544 if (!lookup.IsReadOnly()) {
545 if (lookup.type() != INTERCEPTOR) {
546 return ThrowRedeclarationError("var", name);
547 }
548
549 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
550
551 // Throw re-declaration error if the intercepted property is present
552 // but not read-only.
553 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
554 return ThrowRedeclarationError("var", name);
555 }
556
557 // Restore global object from context (in case of GC) and continue
558 // with setting the value because the property is either absent or
559 // read-only. We also have to do redo the lookup.
560 global = Top::context()->global();
561
562 // BUG 1213579: Handle the case where we have to set a read-only
563 // property through an interceptor and only do it if it's
564 // uninitialized, e.g. the hole. Nirk...
565 global->SetProperty(*name, *value, attributes);
566 return *value;
567 }
568
569 // Set the value, but only we're assigning the initial value to a
570 // constant. For now, we determine this by checking if the
571 // current value is the hole.
572 PropertyType type = lookup.type();
573 if (type == FIELD) {
574 FixedArray* properties = global->properties();
575 int index = lookup.GetFieldIndex();
576 if (properties->get(index)->IsTheHole()) {
577 properties->set(index, *value);
578 }
579 } else if (type == NORMAL) {
580 Dictionary* dictionary = global->property_dictionary();
581 int entry = lookup.GetDictionaryEntry();
582 if (dictionary->ValueAt(entry)->IsTheHole()) {
583 dictionary->ValueAtPut(entry, *value);
584 }
585 } else {
586 // Ignore re-initialization of constants that have already been
587 // assigned a function value.
588 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
589 }
590
591 // Use the set value as the result of the operation.
592 return *value;
593}
594
595
596static Object* Runtime_InitializeConstContextSlot(Arguments args) {
597 HandleScope scope;
598 ASSERT(args.length() == 3);
599
600 Handle<Object> value(args[0]);
601 ASSERT(!value->IsTheHole());
602 CONVERT_ARG_CHECKED(Context, context, 1);
603 Handle<String> name(String::cast(args[2]));
604
605 // Initializations are always done in the function context.
606 context = Handle<Context>(context->fcontext());
607
608 int index;
609 PropertyAttributes attributes;
610 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
611 Handle<Object> context_obj =
612 context->Lookup(name, flags, &index, &attributes);
613
614 // The property should always be present. It is always declared
615 // before being initialized through DeclareContextSlot.
616 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
617
618 // If the slot is in the context, we set it but only if it hasn't
619 // been set before.
620 if (index >= 0) {
621 // The constant context slot should always be in the function
622 // context; not in any outer context nor in the arguments object.
623 ASSERT(context_obj.is_identical_to(context));
624 if (context->get(index)->IsTheHole()) {
625 context->set(index, *value);
626 }
627 return *value;
628 }
629
630 // Otherwise, the slot must be in a JS object extension.
631 Handle<JSObject> context_ext(JSObject::cast(*context_obj));
632
633 // We must initialize the value only if it wasn't initialized
634 // before, e.g. for const declarations in a loop. The property has
635 // the hole value if it wasn't initialized yet. NOTE: We cannot use
636 // GetProperty() to get the current value as it 'unholes' the value.
637 LookupResult lookup;
638 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
639 ASSERT(lookup.IsProperty()); // the property was declared
640 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
641
642 PropertyType type = lookup.type();
643 if (type == FIELD) {
644 FixedArray* properties = context_ext->properties();
645 int index = lookup.GetFieldIndex();
646 if (properties->get(index)->IsTheHole()) {
647 properties->set(index, *value);
648 }
649 } else if (type == NORMAL) {
650 Dictionary* dictionary = context_ext->property_dictionary();
651 int entry = lookup.GetDictionaryEntry();
652 if (dictionary->ValueAt(entry)->IsTheHole()) {
653 dictionary->ValueAtPut(entry, *value);
654 }
655 } else {
656 // We should not reach here. Any real, named property should be
657 // either a field or a dictionary slot.
658 UNREACHABLE();
659 }
660 return *value;
661}
662
663
664static Object* Runtime_RegExpExec(Arguments args) {
665 HandleScope scope;
666 ASSERT(args.length() == 3);
667 CONVERT_CHECKED(JSValue, raw_regexp, args[0]);
668 Handle<JSValue> regexp(raw_regexp);
669 CONVERT_CHECKED(String, raw_subject, args[1]);
670 Handle<String> subject(raw_subject);
671 Handle<Object> index(args[2]);
672 ASSERT(index->IsNumber());
673 return *RegExpImpl::JsreExec(regexp, subject, index);
674}
675
676
677static Object* Runtime_RegExpExecGlobal(Arguments args) {
678 HandleScope scope;
679 ASSERT(args.length() == 2);
680 CONVERT_CHECKED(JSValue, raw_regexp, args[0]);
681 Handle<JSValue> regexp(raw_regexp);
682 CONVERT_CHECKED(String, raw_subject, args[1]);
683 Handle<String> subject(raw_subject);
684 return *RegExpImpl::JsreExecGlobal(regexp, subject);
685}
686
687
688static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
689 HandleScope scope;
690 ASSERT(args.length() == 4);
691 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
692 int index = Smi::cast(args[1])->value();
693 Handle<String> pattern = args.at<String>(2);
694 Handle<String> flags = args.at<String>(3);
695
696 // Compute the regular expression literal.
697 bool has_pending_exception;
698 Handle<Object> regexp =
699 RegExpImpl::CreateRegExpLiteral(pattern, flags, &has_pending_exception);
700 if (has_pending_exception) {
701 ASSERT(Top::has_pending_exception());
702 return Failure::Exception();
703 }
704 literals->set(index, *regexp);
705 return *regexp;
706}
707
708
709static Object* Runtime_FunctionGetName(Arguments args) {
710 NoHandleAllocation ha;
711 ASSERT(args.length() == 1);
712
713 CONVERT_CHECKED(JSFunction, f, args[0]);
714 return f->shared()->name();
715}
716
717
718static Object* Runtime_FunctionGetScript(Arguments args) {
719 HandleScope scope;
720 ASSERT(args.length() == 1);
721
722 CONVERT_CHECKED(JSFunction, fun, args[0]);
723 Handle<Object> script = Handle<Object>(fun->shared()->script());
724 if (!script->IsScript()) return Heap::undefined_value();
725
726 return *GetScriptWrapper(Handle<Script>::cast(script));
727}
728
729
730static Object* Runtime_FunctionGetSourceCode(Arguments args) {
731 NoHandleAllocation ha;
732 ASSERT(args.length() == 1);
733
734 CONVERT_CHECKED(JSFunction, f, args[0]);
735 return f->shared()->GetSourceCode();
736}
737
738
739static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
740 NoHandleAllocation ha;
741 ASSERT(args.length() == 1);
742
743 CONVERT_CHECKED(JSFunction, fun, args[0]);
744 int pos = fun->shared()->start_position();
745 return Smi::FromInt(pos);
746}
747
748
749static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
750 NoHandleAllocation ha;
751 ASSERT(args.length() == 2);
752
753 CONVERT_CHECKED(JSFunction, fun, args[0]);
754 CONVERT_CHECKED(String, name, args[1]);
755 fun->SetInstanceClassName(name);
756 return Heap::undefined_value();
757}
758
759
760static Object* Runtime_FunctionSetLength(Arguments args) {
761 NoHandleAllocation ha;
762 ASSERT(args.length() == 2);
763
764 CONVERT_CHECKED(JSFunction, fun, args[0]);
765 CONVERT_CHECKED(Smi, length, args[1]);
766 fun->shared()->set_length(length->value());
767 return length;
768}
769
770
771static Object* Runtime_FunctionSetPrototype(Arguments args) {
772 HandleScope scope;
773 ASSERT(args.length() == 2);
774
775 CONVERT_CHECKED(JSFunction, fun, args[0]);
776 Accessors::FunctionSetPrototype(fun, args[1], NULL);
777 return args[0]; // return TOS
778}
779
780
781static Object* Runtime_SetCode(Arguments args) {
782 HandleScope scope;
783 ASSERT(args.length() == 2);
784
785 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
786 Handle<JSFunction> target(raw_target);
787 Handle<Object> code = args.at<Object>(1);
788
789 Handle<Context> context(target->context());
790
791 if (!code->IsNull()) {
792 RUNTIME_ASSERT(code->IsJSFunction());
793 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
794 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
795 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
796 return Failure::Exception();
797 }
798 // Set the code, formal parameter count, and the length of the target
799 // function.
800 target->set_code(fun->code());
801 target->shared()->set_length(fun->shared()->length());
802 target->shared()->set_formal_parameter_count(
803 fun->shared()->formal_parameter_count());
kasper.lund7276f142008-07-30 08:49:36 +0000804 // Set the source code of the target function.
805 target->shared()->set_script(fun->shared()->script());
806 target->shared()->set_start_position(fun->shared()->start_position());
807 target->shared()->set_end_position(fun->shared()->end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 context = Handle<Context>(fun->context());
809
810 // Make sure we get a fresh copy of the literal vector to avoid
811 // cross context contamination.
812 int number_of_literals = fun->literals()->length();
813 if (number_of_literals > 0) {
814 Handle<FixedArray> literals =
815 Factory::NewFixedArray(number_of_literals, TENURED);
816 target->set_literals(*literals);
817 }
818 }
819
820 target->set_context(*context);
821 return *target;
822}
823
824
825static Object* CharCodeAt(String* subject, Object* index) {
826 uint32_t i = 0;
827 if (!Array::IndexFromObject(index, &i))
828 return Heap::nan_value();
829 // Flatten the string. If someone wants to get a char at an index
830 // in a cons string, it is likely that more indices will be
831 // accessed.
832 subject->TryFlatten();
833 if (i >= static_cast<uint32_t>(subject->length()))
834 return Heap::nan_value();
835 return Smi::FromInt(subject->Get(i));
836}
837
838
839static Object* Runtime_StringCharCodeAt(Arguments args) {
840 NoHandleAllocation ha;
841 ASSERT(args.length() == 2);
842
843 CONVERT_CHECKED(String, subject, args[0]);
844 Object* index = args[1];
845 return CharCodeAt(subject, index);
846}
847
848
849static Object* Runtime_CharFromCode(Arguments args) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
852 uint32_t code;
853 if (Array::IndexFromObject(args[0], &code)) {
854 if (code <= 0xffff) {
855 return Heap::LookupSingleCharacterStringFromCode(code);
856 }
857 }
858 return Heap::empty_string();
859}
860
861
862static inline void ComputeKMPNextTable(String* pattern, int next_table[]) {
863 int i = 0;
864 int j = -1;
865 next_table[0] = -1;
866
867 Access<StringInputBuffer> buffer(&string_input_buffer);
868 buffer->Reset(pattern);
869 int length = pattern->length();
870 uint16_t p = buffer->GetNext();
871 while (i < length - 1) {
872 while (j > -1 && p != pattern->Get(j)) {
873 j = next_table[j];
874 }
875 i++;
876 j++;
877 p = buffer->GetNext();
878 if (p == pattern->Get(j)) {
879 next_table[i] = next_table[j];
880 } else {
881 next_table[i] = j;
882 }
883 }
884}
885
886
887static Object* Runtime_StringIndexOf(Arguments args) {
888 NoHandleAllocation ha;
889 ASSERT(args.length() == 3);
890
891 CONVERT_CHECKED(String, sub, args[0]);
892 CONVERT_CHECKED(String, pat, args[1]);
893 Object* index = args[2];
894
895 int subject_length = sub->length();
896 int pattern_length = pat->length();
897
898 sub->TryFlatten();
899 pat->TryFlatten();
900
901 uint32_t start_index;
902 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
903 if (pattern_length == 0) return Smi::FromInt(start_index);
904
905 // Searching for one specific character is common. For one
906 // character patterns the KMP algorithm is guaranteed to slow down
907 // the search, so we just run through the subject string.
908 if (pattern_length == 1) {
909 uint16_t pattern_char = pat->Get(0);
910 for (int i = start_index; i < subject_length; i++) {
911 if (sub->Get(i) == pattern_char) {
912 return Smi::FromInt(i);
913 }
914 }
915 return Smi::FromInt(-1);
916 }
917
918 // For patterns with a length larger than one character we use the KMP
919 // algorithm.
920 //
921 // Compute the 'next' table.
922 int* next_table = NewArray<int>(pattern_length);
923 ComputeKMPNextTable(pat, next_table);
924 // Search using the 'next' table.
925 int pattern_index = 0;
926 // We would like to use StringInputBuffer here, but it does not have
927 // the ability to start anywhere but the first character of a
928 // string. It would be nice to have efficient forward-seeking
929 // support on StringInputBuffers.
930 int subject_index = start_index;
931 while (subject_index < subject_length) {
932 uint16_t subject_char = sub->Get(subject_index);
933 while (pattern_index > -1 && pat->Get(pattern_index) != subject_char) {
934 pattern_index = next_table[pattern_index];
935 }
936 pattern_index++;
937 subject_index++;
938 if (pattern_index >= pattern_length) {
939 DeleteArray(next_table);
940 return Smi::FromInt(subject_index - pattern_index);
941 }
942 }
943 DeleteArray(next_table);
944 return Smi::FromInt(-1);
945}
946
947
948static Object* Runtime_StringLastIndexOf(Arguments args) {
949 NoHandleAllocation ha;
950 ASSERT(args.length() == 3);
951
952 CONVERT_CHECKED(String, sub, args[0]);
953 CONVERT_CHECKED(String, pat, args[1]);
954 Object* index = args[2];
955
956 sub->TryFlatten();
957 pat->TryFlatten();
958
959 uint32_t start_index;
960 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
961
962 uint32_t pattern_length = pat->length();
963 uint32_t sub_length = sub->length();
964
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000965 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000966 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000968
969 for (int i = start_index; i >= 0; i--) {
970 bool found = true;
971 for (uint32_t j = 0; j < pattern_length; j++) {
972 if (sub->Get(i + j) != pat->Get(j)) {
973 found = false;
974 break;
975 }
976 }
977 if (found) return Smi::FromInt(i);
978 }
979
980 return Smi::FromInt(-1);
981}
982
983
984static Object* Runtime_StringLocaleCompare(Arguments args) {
985 NoHandleAllocation ha;
986 ASSERT(args.length() == 2);
987
988 CONVERT_CHECKED(String, str1, args[0]);
989 CONVERT_CHECKED(String, str2, args[1]);
990
991 if (str1 == str2) return Smi::FromInt(0); // Equal.
992 int str1_length = str1->length();
993 int str2_length = str2->length();
994
995 // Decide trivial cases without flattening.
996 if (str1_length == 0) {
997 if (str2_length == 0) return Smi::FromInt(0); // Equal.
998 return Smi::FromInt(-str2_length);
999 } else {
1000 if (str2_length == 0) return Smi::FromInt(str1_length);
1001 }
1002
1003 int end = str1_length < str2_length ? str1_length : str2_length;
1004
1005 // No need to flatten if we are going to find the answer on the first
1006 // character. At this point we know there is at least one character
1007 // in each string, due to the trivial case handling above.
1008 int d = str1->Get(0) - str2->Get(0);
1009 if (d != 0) return Smi::FromInt(d);
1010
1011 str1->TryFlatten();
1012 str2->TryFlatten();
1013
1014 static StringInputBuffer buf1;
1015 static StringInputBuffer buf2;
1016
1017 buf1.Reset(str1);
1018 buf2.Reset(str2);
1019
1020 for (int i = 0; i < end; i++) {
1021 uint16_t char1 = buf1.GetNext();
1022 uint16_t char2 = buf2.GetNext();
1023 if (char1 != char2) return Smi::FromInt(char1 - char2);
1024 }
1025
1026 return Smi::FromInt(str1_length - str2_length);
1027}
1028
1029
1030static Object* Runtime_StringSlice(Arguments args) {
1031 NoHandleAllocation ha;
1032 ASSERT(args.length() == 3);
1033
1034 CONVERT_CHECKED(String, value, args[0]);
1035 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1036 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1037
1038 int start = FastD2I(from_number);
1039 int end = FastD2I(to_number);
1040
1041 RUNTIME_ASSERT(end >= start);
1042 RUNTIME_ASSERT(start >= 0);
1043 RUNTIME_ASSERT(end <= value->length());
1044 return value->Slice(start, end);
1045}
1046
1047
1048static Object* Runtime_NumberToRadixString(Arguments args) {
1049 NoHandleAllocation ha;
1050 ASSERT(args.length() == 2);
1051
1052 CONVERT_DOUBLE_CHECKED(value, args[0]);
1053 if (isnan(value)) {
1054 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1055 }
1056 if (isinf(value)) {
1057 if (value < 0) {
1058 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1059 }
1060 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1061 }
1062 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1063 int radix = FastD2I(radix_number);
1064 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1065 char* str = DoubleToRadixCString(value, radix);
1066 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1067 DeleteArray(str);
1068 return result;
1069}
1070
1071
1072static Object* Runtime_NumberToFixed(Arguments args) {
1073 NoHandleAllocation ha;
1074 ASSERT(args.length() == 2);
1075
1076 CONVERT_DOUBLE_CHECKED(value, args[0]);
1077 if (isnan(value)) {
1078 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1079 }
1080 if (isinf(value)) {
1081 if (value < 0) {
1082 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1083 }
1084 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1085 }
1086 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1087 int f = FastD2I(f_number);
1088 RUNTIME_ASSERT(f >= 0);
1089 char* str = DoubleToFixedCString(value, f);
1090 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1091 DeleteArray(str);
1092 return res;
1093}
1094
1095
1096static Object* Runtime_NumberToExponential(Arguments args) {
1097 NoHandleAllocation ha;
1098 ASSERT(args.length() == 2);
1099
1100 CONVERT_DOUBLE_CHECKED(value, args[0]);
1101 if (isnan(value)) {
1102 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1103 }
1104 if (isinf(value)) {
1105 if (value < 0) {
1106 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1107 }
1108 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1109 }
1110 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1111 int f = FastD2I(f_number);
1112 RUNTIME_ASSERT(f >= -1 && f <= 20);
1113 char* str = DoubleToExponentialCString(value, f);
1114 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1115 DeleteArray(str);
1116 return res;
1117}
1118
1119
1120static Object* Runtime_NumberToPrecision(Arguments args) {
1121 NoHandleAllocation ha;
1122 ASSERT(args.length() == 2);
1123
1124 CONVERT_DOUBLE_CHECKED(value, args[0]);
1125 if (isnan(value)) {
1126 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1127 }
1128 if (isinf(value)) {
1129 if (value < 0) {
1130 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1131 }
1132 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1133 }
1134 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1135 int f = FastD2I(f_number);
1136 RUNTIME_ASSERT(f >= 1 && f <= 21);
1137 char* str = DoubleToPrecisionCString(value, f);
1138 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1139 DeleteArray(str);
1140 return res;
1141}
1142
1143
1144// Returns a single character string where first character equals
1145// string->Get(index).
1146static Object* GetCharAt(String* string, uint32_t index) {
1147 if (index < static_cast<uint32_t>(string->length())) {
1148 string->TryFlatten();
1149 return Heap::LookupSingleCharacterStringFromCode(string->Get(index));
1150 }
1151 return *Execution::CharAt(Handle<String>(string), index);
1152}
1153
1154
1155Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1156 // Handle [] indexing on Strings
1157 if (object->IsString()) {
1158 Object* result = GetCharAt(String::cast(*object), index);
1159 if (!result->IsUndefined()) return result;
1160 }
1161
1162 // Handle [] indexing on String objects
1163 if (object->IsStringObjectWithCharacterAt(index)) {
1164 JSValue* js_value = JSValue::cast(*object);
1165 Object* result = GetCharAt(String::cast(js_value->value()), index);
1166 if (!result->IsUndefined()) return result;
1167 }
1168
1169 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
1170 Object* prototype = object->GetPrototype();
1171 return prototype->GetElement(index);
1172 }
1173
1174 return object->GetElement(index);
1175}
1176
1177
1178Object* Runtime::GetObjectProperty(Handle<Object> object, Object* key) {
1179 if (object->IsUndefined() || object->IsNull()) {
1180 HandleScope scope;
1181 Handle<Object> key_handle(key);
1182 Handle<Object> args[2] = { key_handle, object };
1183 Handle<Object> error =
1184 Factory::NewTypeError("non_object_property_load",
1185 HandleVector(args, 2));
1186 return Top::Throw(*error);
1187 }
1188
1189 // Check if the given key is an array index.
1190 uint32_t index;
1191 if (Array::IndexFromObject(key, &index)) {
1192 HandleScope scope;
1193 return GetElementOrCharAt(object, index);
1194 }
1195
1196 // Convert the key to a string - possibly by calling back into JavaScript.
1197 String* name;
1198 if (key->IsString()) {
1199 name = String::cast(key);
1200 } else {
1201 HandleScope scope;
1202 bool has_pending_exception = false;
1203 Handle<Object> converted =
1204 Execution::ToString(Handle<Object>(key), &has_pending_exception);
1205 if (has_pending_exception) return Failure::Exception();
1206 name = String::cast(*converted);
1207 }
1208
1209 // Check if the name is trivially convertable to an index and get
1210 // the element if so.
1211 if (name->AsArrayIndex(&index)) {
1212 HandleScope scope;
1213 return GetElementOrCharAt(object, index);
1214 } else {
1215 PropertyAttributes attr;
1216 return object->GetProperty(name, &attr);
1217 }
1218}
1219
1220
1221static Object* Runtime_GetProperty(Arguments args) {
1222 NoHandleAllocation ha;
1223 ASSERT(args.length() == 2);
1224
1225 Handle<Object> object = args.at<Object>(0);
1226 Object* key = args[1];
1227
1228 return Runtime::GetObjectProperty(object, key);
1229}
1230
1231
1232Object* Runtime::SetObjectProperty(Handle<Object> object,
1233 Handle<Object> key,
1234 Handle<Object> value,
1235 PropertyAttributes attr) {
1236 if (object->IsUndefined() || object->IsNull()) {
1237 HandleScope scope;
1238 Handle<Object> obj(object);
1239 Handle<Object> args[2] = { key, obj };
1240 Handle<Object> error =
1241 Factory::NewTypeError("non_object_property_store",
1242 HandleVector(args, 2));
1243 return Top::Throw(*error);
1244 }
1245
1246 // If the object isn't a JavaScript object, we ignore the store.
1247 if (!object->IsJSObject()) return *value;
1248
1249 // Check if the given key is an array index.
1250 uint32_t index;
1251 if (Array::IndexFromObject(*key, &index)) {
1252 ASSERT(attr == NONE);
1253
1254 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1255 // of a string using [] notation. We need to support this too in
1256 // JavaScript.
1257 // In the case of a String object we just need to redirect the assignment to
1258 // the underlying string if the index is in range. Since the underlying
1259 // string does nothing with the assignment then we can ignore such
1260 // assignments.
1261 if (object->IsStringObjectWithCharacterAt(index))
1262 return *value;
1263
1264 Object* result = JSObject::cast(*object)->SetElement(index, *value);
1265 if (result->IsFailure()) return result;
1266 return *value;
1267 }
1268
1269 if (key->IsString()) {
1270 Object* result;
1271 if (String::cast(*key)->AsArrayIndex(&index)) {
1272 ASSERT(attr == NONE);
1273 result = JSObject::cast(*object)->SetElement(index, *value);
1274 } else {
1275 String::cast(*key)->TryFlatten();
1276 result =
1277 JSObject::cast(*object)->SetProperty(String::cast(*key), *value,
1278 attr);
1279 }
1280 if (result->IsFailure()) return result;
1281 return *value;
1282 }
1283
1284 // Handlify object and value before calling into JavaScript again.
1285 Handle<JSObject> object_handle = Handle<JSObject>::cast(object);
1286 Handle<Object> value_handle = value;
1287
1288 // Call-back into JavaScript to convert the key to a string.
1289 HandleScope scope;
1290 bool has_pending_exception = false;
1291 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1292 if (has_pending_exception) return Failure::Exception();
1293 Handle<String> name = Handle<String>::cast(converted);
1294
1295 if (name->AsArrayIndex(&index)) {
1296 ASSERT(attr == NONE);
1297 return object_handle->SetElement(index, *value_handle);
1298 } else {
1299 return object_handle->SetProperty(*name, *value_handle, attr);
1300 }
1301}
1302
1303
1304static Object* Runtime_AddProperty(Arguments args) {
1305 NoHandleAllocation ha;
1306 ASSERT(args.length() == 4);
1307
1308 CONVERT_CHECKED(JSObject, object, args[0]);
1309 CONVERT_CHECKED(String, name, args[1]);
1310 RUNTIME_ASSERT(!object->HasLocalProperty(name));
1311 CONVERT_CHECKED(Smi, attr_obj, args[3]);
1312
1313 int attr = attr_obj->value();
1314 RUNTIME_ASSERT((attr & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1315 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1316
1317 return object->AddProperty(name, args[2], attributes);
1318}
1319
1320
1321static Object* Runtime_SetProperty(Arguments args) {
1322 NoHandleAllocation ha;
1323 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1324
1325 Handle<Object> object = args.at<Object>(0);
1326 Handle<Object> key = args.at<Object>(1);
1327 Handle<Object> value = args.at<Object>(2);
1328
1329 // Compute attributes.
1330 PropertyAttributes attributes = NONE;
1331 if (args.length() == 4) {
1332 CONVERT_CHECKED(Smi, value_obj, args[3]);
1333 int value = value_obj->value();
1334 // Only attribute bits should be set.
1335 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1336 attributes = static_cast<PropertyAttributes>(value);
1337 }
1338 return Runtime::SetObjectProperty(object, key, value, attributes);
1339}
1340
1341
1342// Set a local property, even if it is READ_ONLY. If the property does not
1343// exist, it will be added with attributes NONE.
1344static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1345 NoHandleAllocation ha;
1346 ASSERT(args.length() == 3);
1347
1348 CONVERT_CHECKED(JSObject, object, args[0]);
1349 CONVERT_CHECKED(String, name, args[1]);
1350
1351 return object->IgnoreAttributesAndSetLocalProperty(name, args[2]);
1352}
1353
1354
1355static Object* Runtime_DeleteProperty(Arguments args) {
1356 NoHandleAllocation ha;
1357 ASSERT(args.length() == 2);
1358
1359 CONVERT_CHECKED(JSObject, object, args[0]);
1360 CONVERT_CHECKED(String, key, args[1]);
1361 return object->DeleteProperty(key);
1362}
1363
1364
1365static Object* Runtime_HasLocalProperty(Arguments args) {
1366 NoHandleAllocation ha;
1367 ASSERT(args.length() == 2);
1368 CONVERT_CHECKED(String, key, args[1]);
1369
1370 // Only JS objects can have properties.
1371 if (args[0]->IsJSObject()) {
1372 JSObject* object = JSObject::cast(args[0]);
1373 if (object->HasLocalProperty(key)) return Heap::true_value();
1374 } else if (args[0]->IsString()) {
1375 // Well, there is one exception: Handle [] on strings.
1376 uint32_t index;
1377 if (key->AsArrayIndex(&index)) {
1378 String* string = String::cast(args[0]);
1379 if (index < static_cast<uint32_t>(string->length()))
1380 return Heap::true_value();
1381 }
1382 }
1383 return Heap::false_value();
1384}
1385
1386
1387static Object* Runtime_HasProperty(Arguments args) {
1388 NoHandleAllocation na;
1389 ASSERT(args.length() == 2);
1390
1391 // Only JS objects can have properties.
1392 if (args[0]->IsJSObject()) {
1393 JSObject* object = JSObject::cast(args[0]);
1394 CONVERT_CHECKED(String, key, args[1]);
1395 if (object->HasProperty(key)) return Heap::true_value();
1396 }
1397 return Heap::false_value();
1398}
1399
1400
1401static Object* Runtime_HasElement(Arguments args) {
1402 NoHandleAllocation na;
1403 ASSERT(args.length() == 2);
1404
1405 // Only JS objects can have elements.
1406 if (args[0]->IsJSObject()) {
1407 JSObject* object = JSObject::cast(args[0]);
1408 CONVERT_CHECKED(Smi, index_obj, args[1]);
1409 uint32_t index = index_obj->value();
1410 if (object->HasElement(index)) return Heap::true_value();
1411 }
1412 return Heap::false_value();
1413}
1414
1415
1416static Object* Runtime_IsPropertyEnumerable(Arguments args) {
1417 NoHandleAllocation ha;
1418 ASSERT(args.length() == 2);
1419
1420 CONVERT_CHECKED(JSObject, object, args[0]);
1421 CONVERT_CHECKED(String, key, args[1]);
1422
1423 uint32_t index;
1424 if (key->AsArrayIndex(&index)) {
1425 return Heap::ToBoolean(object->HasElement(index));
1426 }
1427
1428 LookupResult result;
1429 object->LocalLookup(key, &result);
1430 if (!result.IsProperty()) return Heap::false_value();
1431 return Heap::ToBoolean(!result.IsDontEnum());
1432}
1433
1434
1435static Object* Runtime_GetPropertyNames(Arguments args) {
1436 HandleScope scope;
1437 ASSERT(args.length() == 1);
1438
1439 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1440 Handle<JSObject> object(raw_object);
1441 return *GetKeysFor(object);
1442}
1443
1444
1445// Returns either a FixedArray as Runtime_GetPropertyNames,
1446// or, if the given object has an enum cache that contains
1447// all enumerable properties of the object and its prototypes
1448// have none, the map of the object. This is used to speed up
1449// the check for deletions during a for-in.
1450static Object* Runtime_GetPropertyNamesFast(Arguments args) {
1451 ASSERT(args.length() == 1);
1452
1453 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1454
1455 if (raw_object->IsSimpleEnum()) return raw_object->map();
1456
1457 HandleScope scope;
1458 Handle<JSObject> object(raw_object);
1459 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
1460
1461 // Test again, since cache may have been built by preceding call.
1462 if (object->IsSimpleEnum()) return object->map();
1463
1464 return *content;
1465}
1466
1467
1468static Object* Runtime_GetArgumentsProperty(Arguments args) {
1469 NoHandleAllocation ha;
1470 ASSERT(args.length() == 1);
1471
1472 // Compute the frame holding the arguments.
1473 JavaScriptFrameIterator it;
1474 it.AdvanceToArgumentsFrame();
1475 JavaScriptFrame* frame = it.frame();
1476
1477 // Get the actual number of provided arguments.
1478 const uint32_t n = frame->GetProvidedParametersCount();
1479
1480 // Try to convert the key to an index. If successful and within
1481 // index return the the argument from the frame.
1482 uint32_t index;
1483 if (Array::IndexFromObject(args[0], &index) && index < n) {
1484 return frame->GetParameter(index);
1485 }
1486
1487 // Convert the key to a string.
1488 HandleScope scope;
1489 bool exception = false;
1490 Handle<Object> converted =
1491 Execution::ToString(args.at<Object>(0), &exception);
1492 if (exception) return Failure::Exception();
1493 Handle<String> key = Handle<String>::cast(converted);
1494
1495 // Try to convert the string key into an array index.
1496 if (key->AsArrayIndex(&index)) {
1497 if (index < n) {
1498 return frame->GetParameter(index);
1499 } else {
1500 return Top::initial_object_prototype()->GetElement(index);
1501 }
1502 }
1503
1504 // Handle special arguments properties.
1505 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
1506 if (key->Equals(Heap::callee_symbol())) return frame->function();
1507
1508 // Lookup in the initial Object.prototype object.
1509 return Top::initial_object_prototype()->GetProperty(*key);
1510}
1511
1512
1513static Object* Runtime_ToBool(Arguments args) {
1514 NoHandleAllocation ha;
1515 ASSERT(args.length() == 1);
1516
1517 return args[0]->ToBoolean();
1518}
1519
1520
1521// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
1522// Possible optimizations: put the type string into the oddballs.
1523static Object* Runtime_Typeof(Arguments args) {
1524 NoHandleAllocation ha;
1525
1526 Object* obj = args[0];
1527 if (obj->IsNumber()) return Heap::number_symbol();
1528 HeapObject* heap_obj = HeapObject::cast(obj);
1529
1530 // typeof an undetectable object is 'undefined'
1531 if (heap_obj->map()->is_undetectable())
1532 return Heap::undefined_symbol();
1533
1534 InstanceType instance_type = heap_obj->map()->instance_type();
1535 if (instance_type < FIRST_NONSTRING_TYPE) {
1536 return Heap::string_symbol();
1537 }
1538
1539 switch (instance_type) {
1540 case ODDBALL_TYPE:
1541 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
1542 return Heap::boolean_symbol();
1543 }
1544 if (heap_obj->IsNull()) {
1545 return Heap::object_symbol();
1546 }
1547 ASSERT(heap_obj->IsUndefined());
1548 return Heap::undefined_symbol();
1549 case JS_FUNCTION_TYPE:
1550 return Heap::function_symbol();
1551 default:
1552 // For any kind of object not handled above, the spec rule for
1553 // host objects gives that it is okay to return "object"
1554 return Heap::object_symbol();
1555 }
1556}
1557
1558
1559static Object* Runtime_StringToNumber(Arguments args) {
1560 NoHandleAllocation ha;
1561 ASSERT(args.length() == 1);
1562 CONVERT_CHECKED(String, subject, args[0]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001563 subject->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
1565}
1566
1567
1568static Object* Runtime_StringFromCharCodeArray(Arguments args) {
1569 NoHandleAllocation ha;
1570 ASSERT(args.length() == 1);
1571
1572 CONVERT_CHECKED(JSArray, codes, args[0]);
1573 int length = Smi::cast(codes->length())->value();
1574
1575 // Check if the string can be ASCII.
1576 int i;
1577 for (i = 0; i < length; i++) {
1578 Object* element = codes->GetElement(i);
1579 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
1580 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
1581 break;
1582 }
1583
1584 Object* object = NULL;
1585 if (i == length) { // The string is ASCII.
1586 object = Heap::AllocateRawAsciiString(length);
1587 } else { // The string is not ASCII.
1588 object = Heap::AllocateRawTwoByteString(length);
1589 }
1590
1591 if (object->IsFailure()) return object;
1592 String* result = String::cast(object);
1593 for (int i = 0; i < length; i++) {
1594 Object* element = codes->GetElement(i);
1595 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
1596 result->Set(i, chr & 0xffff);
1597 }
1598 return result;
1599}
1600
1601
1602// kNotEscaped is generated by the following:
1603//
1604// #!/bin/perl
1605// for (my $i = 0; $i < 256; $i++) {
1606// print "\n" if $i % 16 == 0;
1607// my $c = chr($i);
1608// my $escaped = 1;
1609// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
1610// print $escaped ? "0, " : "1, ";
1611// }
1612
1613
1614static bool IsNotEscaped(uint16_t character) {
1615 // Only for 8 bit characters, the rest are always escaped (in a different way)
1616 ASSERT(character < 256);
1617 static const char kNotEscaped[256] = {
1618 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1619 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1620 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
1621 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
1622 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1623 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1624 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1625 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1626 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1627 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1628 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1629 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1630 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1631 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1633 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1634 };
1635 return kNotEscaped[character] != 0;
1636}
1637
1638
1639static Object* Runtime_URIEscape(Arguments args) {
1640 const char hex_chars[] = "0123456789ABCDEF";
1641 NoHandleAllocation ha;
1642 ASSERT(args.length() == 1);
1643 CONVERT_CHECKED(String, source, args[0]);
1644
1645 source->TryFlatten();
1646
1647 int escaped_length = 0;
1648 int length = source->length();
1649 {
1650 Access<StringInputBuffer> buffer(&string_input_buffer);
1651 buffer->Reset(source);
1652 while (buffer->has_more()) {
1653 uint16_t character = buffer->GetNext();
1654 if (character >= 256) {
1655 escaped_length += 6;
1656 } else if (IsNotEscaped(character)) {
1657 escaped_length++;
1658 } else {
1659 escaped_length += 3;
1660 }
1661 // We don't allow strings that are longer than Smi range.
1662 if (!Smi::IsValid(escaped_length)) {
1663 Top::context()->mark_out_of_memory();
1664 return Failure::OutOfMemoryException();
1665 }
1666 }
1667 }
1668 // No length change implies no change. Return original string if no change.
1669 if (escaped_length == length) {
1670 return source;
1671 }
1672 Object* o = Heap::AllocateRawAsciiString(escaped_length);
1673 if (o->IsFailure()) return o;
1674 String* destination = String::cast(o);
1675 int dest_position = 0;
1676
1677 Access<StringInputBuffer> buffer(&string_input_buffer);
1678 buffer->Rewind();
1679 while (buffer->has_more()) {
1680 uint16_t character = buffer->GetNext();
1681 if (character >= 256) {
1682 destination->Set(dest_position, '%');
1683 destination->Set(dest_position+1, 'u');
1684 destination->Set(dest_position+2, hex_chars[character >> 12]);
1685 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
1686 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
1687 destination->Set(dest_position+5, hex_chars[character & 0xf]);
1688 dest_position += 6;
1689 } else if (IsNotEscaped(character)) {
1690 destination->Set(dest_position, character);
1691 dest_position++;
1692 } else {
1693 destination->Set(dest_position, '%');
1694 destination->Set(dest_position+1, hex_chars[character >> 4]);
1695 destination->Set(dest_position+2, hex_chars[character & 0xf]);
1696 dest_position += 3;
1697 }
1698 }
1699 return destination;
1700}
1701
1702
1703static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
1704 static const signed char kHexValue['g'] = {
1705 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1706 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1707 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1708 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
1709 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1710 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1711 -1, 10, 11, 12, 13, 14, 15 };
1712
1713 if (character1 > 'f') return -1;
1714 int hi = kHexValue[character1];
1715 if (hi == -1) return -1;
1716 if (character2 > 'f') return -1;
1717 int lo = kHexValue[character2];
1718 if (lo == -1) return -1;
1719 return (hi << 4) + lo;
1720}
1721
1722
1723static inline int Unescape(String* source, int i, int length, int* step) {
1724 uint16_t character = source->Get(i);
1725 int32_t hi, lo;
1726 if (character == '%' &&
1727 i <= length - 6 &&
1728 source->Get(i + 1) == 'u' &&
1729 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
1730 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
1731 *step = 6;
1732 return (hi << 8) + lo;
1733 } else if (character == '%' &&
1734 i <= length - 3 &&
1735 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
1736 *step = 3;
1737 return lo;
1738 } else {
1739 *step = 1;
1740 return character;
1741 }
1742}
1743
1744
1745static Object* Runtime_URIUnescape(Arguments args) {
1746 NoHandleAllocation ha;
1747 ASSERT(args.length() == 1);
1748 CONVERT_CHECKED(String, source, args[0]);
1749
1750 source->TryFlatten();
1751
1752 bool ascii = true;
1753 int length = source->length();
1754
1755 int unescaped_length = 0;
1756 for (int i = 0; i < length; unescaped_length++) {
1757 int step;
1758 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
1759 ascii = false;
1760 i += step;
1761 }
1762
1763 // No length change implies no change. Return original string if no change.
1764 if (unescaped_length == length)
1765 return source;
1766
1767 Object* o = ascii ?
1768 Heap::AllocateRawAsciiString(unescaped_length) :
1769 Heap::AllocateRawTwoByteString(unescaped_length);
1770 if (o->IsFailure()) return o;
1771 String* destination = String::cast(o);
1772
1773 int dest_position = 0;
1774 for (int i = 0; i < length; dest_position++) {
1775 int step;
1776 destination->Set(dest_position, Unescape(source, i, length, &step));
1777 i += step;
1778 }
1779 return destination;
1780}
1781
1782
1783static Object* Runtime_StringParseInt(Arguments args) {
1784 NoHandleAllocation ha;
1785
1786 CONVERT_CHECKED(String, s, args[0]);
1787 CONVERT_DOUBLE_CHECKED(n, args[1]);
1788 int radix = FastD2I(n);
1789
1790 s->TryFlatten();
1791
1792 int len = s->length();
1793 int i;
1794
1795 // Skip leading white space.
1796 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
1797 if (i == len) return Heap::nan_value();
1798
1799 // Compute the sign (default to +).
1800 int sign = 1;
1801 if (s->Get(i) == '-') {
1802 sign = -1;
1803 i++;
1804 } else if (s->Get(i) == '+') {
1805 i++;
1806 }
1807
1808 // Compute the radix if 0.
1809 if (radix == 0) {
1810 radix = 10;
1811 if (i < len && s->Get(i) == '0') {
1812 radix = 8;
1813 if (i + 1 < len) {
1814 int c = s->Get(i + 1);
1815 if (c == 'x' || c == 'X') {
1816 radix = 16;
1817 i += 2;
1818 }
1819 }
1820 }
1821 } else if (radix == 16) {
1822 // Allow 0x or 0X prefix if radix is 16.
1823 if (i + 1 < len && s->Get(i) == '0') {
1824 int c = s->Get(i + 1);
1825 if (c == 'x' || c == 'X') i += 2;
1826 }
1827 }
1828
1829 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1830 double value;
1831 int end_index = StringToInt(s, i, radix, &value);
1832 if (end_index != i) {
1833 return Heap::NumberFromDouble(sign * value);
1834 }
1835 return Heap::nan_value();
1836}
1837
1838
1839static Object* Runtime_StringParseFloat(Arguments args) {
1840 NoHandleAllocation ha;
1841 CONVERT_CHECKED(String, str, args[0]);
1842
1843 // ECMA-262 section 15.1.2.3, empty string is NaN
1844 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
1845
1846 // Create a number object from the value.
1847 return Heap::NumberFromDouble(value);
1848}
1849
1850
1851static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
1852static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
1853
1854
1855template <class Converter>
1856static Object* ConvertCase(Arguments args,
1857 unibrow::Mapping<Converter, 128> *mapping) {
1858 NoHandleAllocation ha;
1859
1860 CONVERT_CHECKED(String, s, args[0]);
1861 int raw_string_length = s->length();
1862 // Assume that the string is not empty; we need this assumption later
1863 if (raw_string_length == 0) return s;
1864 int length = raw_string_length;
1865
1866 s->TryFlatten();
1867
1868 // We try this twice, once with the assumption that the result is
1869 // no longer than the input and, if that assumption breaks, again
1870 // with the exact length. This is implemented using a goto back
1871 // to this label if we discover that the assumption doesn't hold.
1872 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00001873 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001874 try_convert:
1875
1876 // Allocate the resulting string.
1877 //
1878 // NOTE: This assumes that the upper/lower case of an ascii
1879 // character is also ascii. This is currently the case, but it
1880 // might break in the future if we implement more context and locale
1881 // dependent upper/lower conversions.
1882 Object* o = s->IsAscii()
1883 ? Heap::AllocateRawAsciiString(length)
1884 : Heap::AllocateRawTwoByteString(length);
1885 if (o->IsFailure())
1886 return o;
1887 String* result = String::cast(o);
1888 bool has_changed_character = false;
1889
1890
1891 // Convert all characters to upper case, assuming that they will fit
1892 // in the buffer
1893 Access<StringInputBuffer> buffer(&string_input_buffer);
1894 buffer->Reset(s);
1895 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
1896 int i = 0;
1897 // We can assume that the string is not empty
1898 uc32 current = buffer->GetNext();
1899 while (i < length) {
1900 uc32 next = buffer->has_more() ? buffer->GetNext() : 0;
1901 int char_length = mapping->get(current, next, chars);
1902 if (char_length == 0) {
1903 // The case conversion of this character is the character itself.
1904 result->Set(i, current);
1905 i++;
1906 } else if (char_length == 1) {
1907 // Common case: converting the letter resulted in one character.
1908 ASSERT(static_cast<uc32>(chars[0]) != current);
1909 result->Set(i, chars[0]);
1910 has_changed_character = true;
1911 i++;
1912 } else if (length == raw_string_length) {
1913 // We've assumed that the result would be as long as the
1914 // input but here is a character that converts to several
1915 // characters. No matter, we calculate the exact length
1916 // of the result and try the whole thing again.
1917 //
1918 // Note that this leaves room for optimization. We could just
1919 // memcpy what we already have to the result string. Also,
1920 // the result string is the last object allocated we could
1921 // "realloc" it and probably, in the vast majority of cases,
1922 // extend the existing string to be able to hold the full
1923 // result.
1924 int current_length = i + char_length + mapping->get(next, 0, chars);
1925 while (buffer->has_more()) {
1926 current = buffer->GetNext();
1927 int char_length = mapping->get(current, 0, chars);
1928 if (char_length == 0) char_length = 1;
1929 current += char_length;
1930 }
1931 length = current_length;
1932 goto try_convert;
1933 } else {
1934 for (int j = 0; j < char_length; j++) {
1935 result->Set(i, chars[j]);
1936 i++;
1937 }
1938 has_changed_character = true;
1939 }
1940 current = next;
1941 }
1942 if (has_changed_character) {
1943 return result;
1944 } else {
1945 // If we didn't actually change anything in doing the conversion
1946 // we simple return the result and let the converted string
1947 // become garbage; there is no reason to keep two identical strings
1948 // alive.
1949 return s;
1950 }
1951}
1952
1953
1954static Object* Runtime_StringToLowerCase(Arguments args) {
1955 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
1956}
1957
1958
1959static Object* Runtime_StringToUpperCase(Arguments args) {
1960 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
1961}
1962
1963
1964static Object* Runtime_ConsStringFst(Arguments args) {
1965 NoHandleAllocation ha;
1966
1967 CONVERT_CHECKED(ConsString, str, args[0]);
1968 return str->first();
1969}
1970
1971
1972static Object* Runtime_ConsStringSnd(Arguments args) {
1973 NoHandleAllocation ha;
1974
1975 CONVERT_CHECKED(ConsString, str, args[0]);
1976 return str->second();
1977}
1978
1979
1980static Object* Runtime_NumberToString(Arguments args) {
1981 NoHandleAllocation ha;
1982 ASSERT(args.length() == 1);
1983
1984 Object* number = args[0];
1985 RUNTIME_ASSERT(number->IsNumber());
1986
1987 Object* cached = Heap::GetNumberStringCache(number);
1988 if (cached != Heap::undefined_value()) {
1989 return cached;
1990 }
1991
1992 char arr[100];
1993 Vector<char> buffer(arr, ARRAY_SIZE(arr));
1994 const char* str;
1995 if (number->IsSmi()) {
1996 int num = Smi::cast(number)->value();
1997 str = IntToCString(num, buffer);
1998 } else {
1999 double num = HeapNumber::cast(number)->value();
2000 str = DoubleToCString(num, buffer);
2001 }
2002 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2003
2004 if (!result->IsFailure()) {
2005 Heap::SetNumberStringCache(number, String::cast(result));
2006 }
2007 return result;
2008}
2009
2010
2011static Object* Runtime_NumberToInteger(Arguments args) {
2012 NoHandleAllocation ha;
2013 ASSERT(args.length() == 1);
2014
2015 Object* obj = args[0];
2016
2017 if (obj->IsSmi())
2018 return obj;
2019
2020 CONVERT_DOUBLE_CHECKED(number, obj);
2021 return Heap::NumberFromDouble(DoubleToInteger(number));
2022}
2023
2024
2025static Object* Runtime_NumberToJSUint32(Arguments args) {
2026 NoHandleAllocation ha;
2027 ASSERT(args.length() == 1);
2028
2029 Object* obj = args[0];
2030 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2031 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2032 return Heap::NumberFromUint32(number);
2033}
2034
2035
2036static Object* Runtime_NumberToJSInt32(Arguments args) {
2037 NoHandleAllocation ha;
2038 ASSERT(args.length() == 1);
2039
2040 Object* obj = args[0];
2041 if (obj->IsSmi()) return obj;
2042 CONVERT_DOUBLE_CHECKED(number, obj);
2043 return Heap::NumberFromInt32(DoubleToInt32(number));
2044}
2045
2046
2047static Object* Runtime_NumberAdd(Arguments args) {
2048 NoHandleAllocation ha;
2049 ASSERT(args.length() == 2);
2050
2051 CONVERT_DOUBLE_CHECKED(x, args[0]);
2052 CONVERT_DOUBLE_CHECKED(y, args[1]);
2053 return Heap::AllocateHeapNumber(x + y);
2054}
2055
2056
2057static Object* Runtime_NumberSub(Arguments args) {
2058 NoHandleAllocation ha;
2059 ASSERT(args.length() == 2);
2060
2061 CONVERT_DOUBLE_CHECKED(x, args[0]);
2062 CONVERT_DOUBLE_CHECKED(y, args[1]);
2063 return Heap::AllocateHeapNumber(x - y);
2064}
2065
2066
2067static Object* Runtime_NumberMul(Arguments args) {
2068 NoHandleAllocation ha;
2069 ASSERT(args.length() == 2);
2070
2071 CONVERT_DOUBLE_CHECKED(x, args[0]);
2072 CONVERT_DOUBLE_CHECKED(y, args[1]);
2073 return Heap::AllocateHeapNumber(x * y);
2074}
2075
2076
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002077static Object* Runtime_NumberUnaryMinus(Arguments args) {
2078 NoHandleAllocation ha;
2079 ASSERT(args.length() == 1);
2080
2081 CONVERT_DOUBLE_CHECKED(x, args[0]);
2082 return Heap::AllocateHeapNumber(-x);
2083}
2084
2085
2086static Object* Runtime_NumberDiv(Arguments args) {
2087 NoHandleAllocation ha;
2088 ASSERT(args.length() == 2);
2089
2090 CONVERT_DOUBLE_CHECKED(x, args[0]);
2091 CONVERT_DOUBLE_CHECKED(y, args[1]);
2092 return Heap::NewNumberFromDouble(x / y);
2093}
2094
2095
2096static Object* Runtime_NumberMod(Arguments args) {
2097 NoHandleAllocation ha;
2098 ASSERT(args.length() == 2);
2099
2100 CONVERT_DOUBLE_CHECKED(x, args[0]);
2101 CONVERT_DOUBLE_CHECKED(y, args[1]);
2102
2103#ifdef WIN32
2104 // Workaround MS fmod bugs. ECMA-262 says:
2105 // dividend is finite and divisor is an infinity => result equals dividend
2106 // dividend is a zero and divisor is nonzero finite => result equals dividend
2107 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2108 !(x == 0 && (y != 0 && isfinite(y))))
2109#endif
2110 x = fmod(x, y);
2111 // NewNumberFromDouble may return a Smi instead of a Number object
2112 return Heap::NewNumberFromDouble(x);
2113}
2114
2115
2116static Object* Runtime_StringAdd(Arguments args) {
2117 NoHandleAllocation ha;
2118 ASSERT(args.length() == 2);
2119
2120 CONVERT_CHECKED(String, str1, args[0]);
2121 CONVERT_CHECKED(String, str2, args[1]);
2122 int len1 = str1->length();
2123 int len2 = str2->length();
2124 if (len1 == 0) return str2;
2125 if (len2 == 0) return str1;
2126 int length_sum = len1 + len2;
2127 // Make sure that an out of memory exception is thrown if the length
2128 // of the new cons string is too large to fit in a Smi.
2129 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2130 Top::context()->mark_out_of_memory();
2131 return Failure::OutOfMemoryException();
2132 }
2133 return Heap::AllocateConsString(str1, str2);
2134}
2135
2136
2137static Object* Runtime_StringBuilderConcat(Arguments args) {
2138 NoHandleAllocation ha;
2139 ASSERT(args.length() == 2);
2140 CONVERT_CHECKED(JSArray, array, args[0]);
2141 CONVERT_CHECKED(String, special, args[1]);
2142 int special_length = special->length();
2143 Object* smi_array_length = array->length();
2144 if (!smi_array_length->IsSmi()) {
2145 Top::context()->mark_out_of_memory();
2146 return Failure::OutOfMemoryException();
2147 }
2148 int array_length = Smi::cast(smi_array_length)->value();
2149 if (!array->HasFastElements()) {
2150 return Top::Throw(Heap::illegal_argument_symbol());
2151 }
2152 FixedArray* fixed_array = FixedArray::cast(array->elements());
2153 if (fixed_array->length() < array_length)
2154 array_length = fixed_array->length();
2155
2156 if (array_length == 0) {
2157 return Heap::empty_string();
2158 } else if (array_length == 1) {
2159 Object* first = fixed_array->get(0);
2160 if (first->IsString()) return first;
2161 }
2162
2163 bool ascii = special->IsAscii();
2164 int position = 0;
2165 for (int i = 0; i < array_length; i++) {
2166 Object* elt = fixed_array->get(i);
2167 if (elt->IsSmi()) {
2168 int len = Smi::cast(elt)->value();
2169 int pos = len >> 11;
2170 len &= 0x7ff;
2171 if (pos + len > special_length) {
2172 return Top::Throw(Heap::illegal_argument_symbol());
2173 }
2174 position += len;
2175 } else if (elt->IsString()) {
2176 String* element = String::cast(elt);
2177 int element_length = element->length();
2178 if (!Smi::IsValid(element_length + position)) {
2179 Top::context()->mark_out_of_memory();
2180 return Failure::OutOfMemoryException();
2181 }
2182 position += element_length;
2183 if (ascii && !element->IsAscii())
2184 ascii = false;
2185 } else {
2186 return Top::Throw(Heap::illegal_argument_symbol());
2187 }
2188 }
2189
2190 int length = position;
2191 position = 0;
2192 Object* object;
2193 if (ascii) {
2194 object = Heap::AllocateRawAsciiString(length);
2195 } else {
2196 object = Heap::AllocateRawTwoByteString(length);
2197 }
2198 if (object->IsFailure()) return object;
2199
2200 String* answer = String::cast(object);
2201 for (int i = 0; i < array_length; i++) {
2202 Object* element = fixed_array->get(i);
2203 if (element->IsSmi()) {
2204 int len = Smi::cast(element)->value();
2205 int pos = len >> 11;
2206 len &= 0x7ff;
2207 String::Flatten(special, answer, pos, pos + len, position);
2208 position += len;
2209 } else {
2210 String* string = String::cast(element);
2211 int element_length = string->length();
2212 String::Flatten(string, answer, 0, element_length, position);
2213 position += element_length;
2214 }
2215 }
2216 return answer;
2217}
2218
2219
2220static Object* Runtime_NumberOr(Arguments args) {
2221 NoHandleAllocation ha;
2222 ASSERT(args.length() == 2);
2223
2224 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2225 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2226 return Heap::NumberFromInt32(x | y);
2227}
2228
2229
2230static Object* Runtime_NumberAnd(Arguments args) {
2231 NoHandleAllocation ha;
2232 ASSERT(args.length() == 2);
2233
2234 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2235 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2236 return Heap::NumberFromInt32(x & y);
2237}
2238
2239
2240static Object* Runtime_NumberXor(Arguments args) {
2241 NoHandleAllocation ha;
2242 ASSERT(args.length() == 2);
2243
2244 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2245 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2246 return Heap::NumberFromInt32(x ^ y);
2247}
2248
2249
2250static Object* Runtime_NumberNot(Arguments args) {
2251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 1);
2253
2254 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2255 return Heap::NumberFromInt32(~x);
2256}
2257
2258
2259static Object* Runtime_NumberShl(Arguments args) {
2260 NoHandleAllocation ha;
2261 ASSERT(args.length() == 2);
2262
2263 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2264 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2265 return Heap::NumberFromInt32(x << (y & 0x1f));
2266}
2267
2268
2269static Object* Runtime_NumberShr(Arguments args) {
2270 NoHandleAllocation ha;
2271 ASSERT(args.length() == 2);
2272
2273 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2274 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2275 return Heap::NumberFromUint32(x >> (y & 0x1f));
2276}
2277
2278
2279static Object* Runtime_NumberSar(Arguments args) {
2280 NoHandleAllocation ha;
2281 ASSERT(args.length() == 2);
2282
2283 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2284 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2285 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2286}
2287
2288
2289static Object* Runtime_ObjectEquals(Arguments args) {
2290 NoHandleAllocation ha;
2291 ASSERT(args.length() == 2);
2292
2293 return Smi::FromInt(args[0] == args[1] ? EQUAL : NOT_EQUAL);
2294}
2295
2296
2297static Object* Runtime_NumberEquals(Arguments args) {
2298 NoHandleAllocation ha;
2299 ASSERT(args.length() == 2);
2300
2301 CONVERT_DOUBLE_CHECKED(x, args[0]);
2302 CONVERT_DOUBLE_CHECKED(y, args[1]);
2303 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
2304 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
2305 if (x == y) return Smi::FromInt(EQUAL);
2306 Object* result;
2307 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
2308 result = Smi::FromInt(EQUAL);
2309 } else {
2310 result = Smi::FromInt(NOT_EQUAL);
2311 }
2312 return result;
2313}
2314
2315
2316static Object* Runtime_StringEquals(Arguments args) {
2317 NoHandleAllocation ha;
2318 ASSERT(args.length() == 2);
2319
2320 CONVERT_CHECKED(String, x, args[0]);
2321 CONVERT_CHECKED(String, y, args[1]);
2322
2323 // This is very similar to String::Equals(String*) but that version
2324 // requires flattened strings as input, whereas we flatten the
2325 // strings only if the fast cases fail. Note that this may fail,
2326 // requiring a GC. String::Equals(String*) returns a bool and has
2327 // no way to signal a failure.
2328 if (y == x) return Smi::FromInt(EQUAL);
2329 if (x->IsSymbol() && y->IsSymbol()) return Smi::FromInt(NOT_EQUAL);
2330 // Compare contents
2331 int len = x->length();
2332 if (len != y->length()) return Smi::FromInt(NOT_EQUAL);
2333 if (len == 0) return Smi::FromInt(EQUAL);
2334 // Fast case: First, middle and last characters.
2335 if (x->Get(0) != y->Get(0)) return Smi::FromInt(NOT_EQUAL);
2336 if (x->Get(len>>1) != y->Get(len>>1)) return Smi::FromInt(NOT_EQUAL);
2337 if (x->Get(len - 1) != y->Get(len - 1)) return Smi::FromInt(NOT_EQUAL);
2338
2339 x->TryFlatten();
2340 y->TryFlatten();
2341
2342 static StringInputBuffer buf1;
2343 static StringInputBuffer buf2;
2344 buf1.Reset(x);
2345 buf2.Reset(y);
2346 while (buf1.has_more()) {
2347 if (buf1.GetNext() != buf2.GetNext())
2348 return Smi::FromInt(NOT_EQUAL);
2349 }
2350 return Smi::FromInt(EQUAL);
2351}
2352
2353
2354static Object* Runtime_NumberCompare(Arguments args) {
2355 NoHandleAllocation ha;
2356 ASSERT(args.length() == 3);
2357
2358 CONVERT_DOUBLE_CHECKED(x, args[0]);
2359 CONVERT_DOUBLE_CHECKED(y, args[1]);
2360 if (isnan(x) || isnan(y)) return args[2];
2361 if (x == y) return Smi::FromInt(EQUAL);
2362 if (isless(x, y)) return Smi::FromInt(LESS);
2363 return Smi::FromInt(GREATER);
2364}
2365
2366
2367static Object* Runtime_StringCompare(Arguments args) {
2368 NoHandleAllocation ha;
2369 ASSERT(args.length() == 2);
2370
2371 CONVERT_CHECKED(String, x, args[0]);
2372 CONVERT_CHECKED(String, y, args[1]);
2373
2374 // A few fast case tests before we flatten.
2375 if (x == y) return Smi::FromInt(EQUAL);
2376 if (y->length() == 0) {
2377 if (x->length() == 0)
2378 return Smi::FromInt(EQUAL);
2379 return Smi::FromInt(GREATER);
2380 } else if (x->length() == 0) {
2381 return Smi::FromInt(LESS);
2382 }
2383 {
2384 int d = x->Get(0) - y->Get(0);
2385 if (d < 0) return Smi::FromInt(LESS);
2386 else if (d > 0) return Smi::FromInt(GREATER);
2387 }
2388
2389 x->TryFlatten();
2390 y->TryFlatten();
2391
2392 static StringInputBuffer bufx;
2393 static StringInputBuffer bufy;
2394 bufx.Reset(x);
2395 bufy.Reset(y);
2396 while (bufx.has_more() && bufy.has_more()) {
2397 int d = bufx.GetNext() - bufy.GetNext();
2398 if (d < 0) return Smi::FromInt(LESS);
2399 else if (d > 0) return Smi::FromInt(GREATER);
2400 }
2401
2402 // x is (non-trivial) prefix of y:
2403 if (bufy.has_more()) return Smi::FromInt(LESS);
2404 // y is prefix of x:
2405 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
2406}
2407
2408
2409static Object* Runtime_Math_abs(Arguments args) {
2410 NoHandleAllocation ha;
2411 ASSERT(args.length() == 1);
2412
2413 CONVERT_DOUBLE_CHECKED(x, args[0]);
2414 return Heap::AllocateHeapNumber(fabs(x));
2415}
2416
2417
2418static Object* Runtime_Math_acos(Arguments args) {
2419 NoHandleAllocation ha;
2420 ASSERT(args.length() == 1);
2421
2422 CONVERT_DOUBLE_CHECKED(x, args[0]);
2423 return Heap::AllocateHeapNumber(acos(x));
2424}
2425
2426
2427static Object* Runtime_Math_asin(Arguments args) {
2428 NoHandleAllocation ha;
2429 ASSERT(args.length() == 1);
2430
2431 CONVERT_DOUBLE_CHECKED(x, args[0]);
2432 return Heap::AllocateHeapNumber(asin(x));
2433}
2434
2435
2436static Object* Runtime_Math_atan(Arguments args) {
2437 NoHandleAllocation ha;
2438 ASSERT(args.length() == 1);
2439
2440 CONVERT_DOUBLE_CHECKED(x, args[0]);
2441 return Heap::AllocateHeapNumber(atan(x));
2442}
2443
2444
2445static Object* Runtime_Math_atan2(Arguments args) {
2446 NoHandleAllocation ha;
2447 ASSERT(args.length() == 2);
2448
2449 CONVERT_DOUBLE_CHECKED(x, args[0]);
2450 CONVERT_DOUBLE_CHECKED(y, args[1]);
2451 double result;
2452 if (isinf(x) && isinf(y)) {
2453 // Make sure that the result in case of two infinite arguments
2454 // is a multiple of Pi / 4. The sign of the result is determined
2455 // by the first argument (x) and the sign of the second argument
2456 // determines the multiplier: one or three.
2457 static double kPiDividedBy4 = 0.78539816339744830962;
2458 int multiplier = (x < 0) ? -1 : 1;
2459 if (y < 0) multiplier *= 3;
2460 result = multiplier * kPiDividedBy4;
2461 } else {
2462 result = atan2(x, y);
2463 }
2464 return Heap::AllocateHeapNumber(result);
2465}
2466
2467
2468static Object* Runtime_Math_ceil(Arguments args) {
2469 NoHandleAllocation ha;
2470 ASSERT(args.length() == 1);
2471
2472 CONVERT_DOUBLE_CHECKED(x, args[0]);
2473 return Heap::NumberFromDouble(ceiling(x));
2474}
2475
2476
2477static Object* Runtime_Math_cos(Arguments args) {
2478 NoHandleAllocation ha;
2479 ASSERT(args.length() == 1);
2480
2481 CONVERT_DOUBLE_CHECKED(x, args[0]);
2482 return Heap::AllocateHeapNumber(cos(x));
2483}
2484
2485
2486static Object* Runtime_Math_exp(Arguments args) {
2487 NoHandleAllocation ha;
2488 ASSERT(args.length() == 1);
2489
2490 CONVERT_DOUBLE_CHECKED(x, args[0]);
2491 return Heap::AllocateHeapNumber(exp(x));
2492}
2493
2494
2495static Object* Runtime_Math_floor(Arguments args) {
2496 NoHandleAllocation ha;
2497 ASSERT(args.length() == 1);
2498
2499 CONVERT_DOUBLE_CHECKED(x, args[0]);
2500 return Heap::NumberFromDouble(floor(x));
2501}
2502
2503
2504static Object* Runtime_Math_log(Arguments args) {
2505 NoHandleAllocation ha;
2506 ASSERT(args.length() == 1);
2507
2508 CONVERT_DOUBLE_CHECKED(x, args[0]);
2509 return Heap::AllocateHeapNumber(log(x));
2510}
2511
2512
2513static Object* Runtime_Math_pow(Arguments args) {
2514 NoHandleAllocation ha;
2515 ASSERT(args.length() == 2);
2516
2517 CONVERT_DOUBLE_CHECKED(x, args[0]);
2518 CONVERT_DOUBLE_CHECKED(y, args[1]);
2519 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
2520 return Heap::nan_value();
2521 } else if (y == 0) {
2522 return Smi::FromInt(1);
2523 } else {
2524 return Heap::AllocateHeapNumber(pow(x, y));
2525 }
2526}
2527
2528// Returns a number value with positive sign, greater than or equal to
2529// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00002530static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002531 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00002532 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002533
2534 // To get much better precision, we combine the results of two
2535 // invocations of random(). The result is computed by normalizing a
2536 // double in the range [0, RAND_MAX + 1) obtained by adding the
2537 // high-order bits in the range [0, RAND_MAX] with the low-order
2538 // bits in the range [0, 1).
2539 double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
2540 double hi = static_cast<double>(random());
2541 double result = (hi + lo) / (RAND_MAX + 1.0);
2542 ASSERT(result >= 0 && result < 1);
2543 return Heap::AllocateHeapNumber(result);
2544}
2545
2546
2547static Object* Runtime_Math_round(Arguments args) {
2548 NoHandleAllocation ha;
2549 ASSERT(args.length() == 1);
2550
2551 CONVERT_DOUBLE_CHECKED(x, args[0]);
2552 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
2553 return Heap::NumberFromDouble(floor(x + 0.5));
2554}
2555
2556
2557static Object* Runtime_Math_sin(Arguments args) {
2558 NoHandleAllocation ha;
2559 ASSERT(args.length() == 1);
2560
2561 CONVERT_DOUBLE_CHECKED(x, args[0]);
2562 return Heap::AllocateHeapNumber(sin(x));
2563}
2564
2565
2566static Object* Runtime_Math_sqrt(Arguments args) {
2567 NoHandleAllocation ha;
2568 ASSERT(args.length() == 1);
2569
2570 CONVERT_DOUBLE_CHECKED(x, args[0]);
2571 return Heap::AllocateHeapNumber(sqrt(x));
2572}
2573
2574
2575static Object* Runtime_Math_tan(Arguments args) {
2576 NoHandleAllocation ha;
2577 ASSERT(args.length() == 1);
2578
2579 CONVERT_DOUBLE_CHECKED(x, args[0]);
2580 return Heap::AllocateHeapNumber(tan(x));
2581}
2582
2583
2584static Object* Runtime_NewArguments(Arguments args) {
2585 NoHandleAllocation ha;
2586 ASSERT(args.length() == 1);
2587
2588 // ECMA-262, 3rd., 10.1.8, p.39
2589 CONVERT_CHECKED(JSFunction, callee, args[0]);
2590
2591 // Compute the frame holding the arguments.
2592 JavaScriptFrameIterator it;
2593 it.AdvanceToArgumentsFrame();
2594 JavaScriptFrame* frame = it.frame();
2595
2596 const int length = frame->GetProvidedParametersCount();
2597 Object* result = Heap::AllocateArgumentsObject(callee, length);
2598 if (result->IsFailure()) return result;
2599 FixedArray* array = FixedArray::cast(JSObject::cast(result)->elements());
2600 ASSERT(array->length() == length);
2601 for (int i = 0; i < length; i++) {
2602 array->set(i, frame->GetParameter(i));
2603 }
2604 return result;
2605}
2606
2607
2608static Object* Runtime_NewClosure(Arguments args) {
2609 HandleScope scope;
2610 ASSERT(args.length() == 2);
2611 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
2612 CONVERT_ARG_CHECKED(Context, context, 1);
2613
2614 Handle<JSFunction> result =
2615 Factory::NewFunctionFromBoilerplate(boilerplate, context);
2616 return *result;
2617}
2618
2619
2620static Object* Runtime_NewObject(Arguments args) {
2621 NoHandleAllocation ha;
2622 ASSERT(args.length() == 1);
2623
2624 Object* constructor = args[0];
2625 if (constructor->IsJSFunction()) {
2626 JSFunction* function = JSFunction::cast(constructor);
2627
2628 // Handle steping into constructors.
2629 if (Debug::StepInActive()) {
2630 StackFrameIterator it;
2631 it.Advance();
2632 ASSERT(InternalFrame::cast(it.frame())->is_construct_trampoline());
2633 it.Advance();
2634 if (it.frame()->fp() == Debug::step_in_fp()) {
2635 HandleScope scope;
2636 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
2637 }
2638 }
2639
2640 if (function->has_initial_map() &&
2641 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
2642 // The 'Function' function ignores the receiver object when
2643 // called using 'new' and creates a new JSFunction object that
2644 // is returned. The receiver object is only used for error
2645 // reporting if an error occurs when constructing the new
2646 // JSFunction. AllocateJSObject should not be used to allocate
2647 // JSFunctions since it does not properly initialize the shared
2648 // part of the function. Since the receiver is ignored anyway,
2649 // we use the global object as the receiver instead of a new
2650 // JSFunction object. This way, errors are reported the same
2651 // way whether or not 'Function' is called using 'new'.
2652 return Top::context()->global();
2653 }
2654 return Heap::AllocateJSObject(function);
2655 }
2656
2657 HandleScope scope;
2658 Handle<Object> cons(constructor);
2659 // The constructor is not a function; throw a type error.
2660 Handle<Object> type_error =
2661 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
2662 return Top::Throw(*type_error);
2663}
2664
2665
2666#ifdef DEBUG
2667DEFINE_bool(trace_lazy, false, "trace lazy compilation");
2668#endif
2669
2670
2671static Object* Runtime_LazyCompile(Arguments args) {
2672 HandleScope scope;
2673 ASSERT(args.length() == 1);
2674
2675 Handle<JSFunction> function = args.at<JSFunction>(0);
2676#ifdef DEBUG
2677 if (FLAG_trace_lazy) {
2678 PrintF("[lazy: ");
2679 function->shared()->name()->Print();
2680 PrintF("]\n");
2681 }
2682#endif
2683
2684 // Compile the target function.
2685 ASSERT(!function->is_compiled());
2686 if (!CompileLazy(function, KEEP_EXCEPTION)) {
2687 return Failure::Exception();
2688 }
2689
2690 return function->code();
2691}
2692
2693
2694static Object* Runtime_GetCalledFunction(Arguments args) {
2695 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00002696 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002697 StackFrameIterator it;
2698 // Get past the JS-to-C exit frame.
2699 ASSERT(it.frame()->is_exit());
2700 it.Advance();
2701 // Get past the CALL_NON_FUNCTION activation frame.
2702 ASSERT(it.frame()->is_java_script());
2703 it.Advance();
2704 // Argument adaptor frames do not copy the function; we have to skip
2705 // past them to get to the real calling frame.
2706 if (it.frame()->is_arguments_adaptor()) it.Advance();
2707 // Get the function from the top of the expression stack of the
2708 // calling frame.
2709 StandardFrame* frame = StandardFrame::cast(it.frame());
2710 int index = frame->ComputeExpressionsCount() - 1;
2711 Object* result = frame->GetExpression(index);
2712 return result;
2713}
2714
2715
2716static Object* Runtime_GetFunctionDelegate(Arguments args) {
2717 HandleScope scope;
2718 ASSERT(args.length() == 1);
2719 RUNTIME_ASSERT(!args[0]->IsJSFunction());
2720 return *Execution::GetFunctionDelegate(args.at<Object>(0));
2721}
2722
2723
2724static Object* Runtime_NewContext(Arguments args) {
2725 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00002726 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002727
kasper.lund7276f142008-07-30 08:49:36 +00002728 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002729 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
2730 Object* result = Heap::AllocateFunctionContext(length, function);
2731 if (result->IsFailure()) return result;
2732
2733 Top::set_context(Context::cast(result));
2734
kasper.lund7276f142008-07-30 08:49:36 +00002735 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002736}
2737
2738
2739static Object* Runtime_PushContext(Arguments args) {
2740 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00002741 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002742
2743 // Convert the object to a proper JavaScript object.
kasper.lund7276f142008-07-30 08:49:36 +00002744 Object* object = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002745 if (!object->IsJSObject()) {
2746 object = object->ToObject();
2747 if (object->IsFailure()) {
2748 if (!Failure::cast(object)->IsInternalError()) return object;
2749 HandleScope scope;
kasper.lund7276f142008-07-30 08:49:36 +00002750 Handle<Object> handle(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002751 Handle<Object> result =
2752 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
2753 return Top::Throw(*result);
2754 }
2755 }
2756
2757 Object* result =
2758 Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
2759 if (result->IsFailure()) return result;
2760
2761 Top::set_context(Context::cast(result));
2762
kasper.lund7276f142008-07-30 08:49:36 +00002763 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002764}
2765
2766
2767static Object* Runtime_LookupContext(Arguments args) {
2768 HandleScope scope;
2769 ASSERT(args.length() == 2);
2770
2771 CONVERT_ARG_CHECKED(Context, context, 0);
2772 CONVERT_ARG_CHECKED(String, name, 1);
2773
2774 int index;
2775 PropertyAttributes attributes;
2776 ContextLookupFlags flags = FOLLOW_CHAINS;
2777 Handle<Object> context_obj =
2778 context->Lookup(name, flags, &index, &attributes);
2779
2780 if (index < 0 && *context_obj != NULL) {
2781 ASSERT(context_obj->IsJSObject());
2782 return *context_obj;
2783 }
2784
2785 // No intermediate context found. Use global object by default.
2786 return Top::context()->global();
2787}
2788
2789
2790
2791
2792// A mechanism to return pairs of Object*'s. This is somewhat
2793// compiler-dependent as it assumes that a 64-bit value (a long long)
2794// is returned via two registers (edx:eax on ia32). Both the ia32 and
2795// arm platform support this; it is mostly an issue of "coaxing" the
2796// compiler to do the right thing.
2797//
2798// TODO(1236026): This is a non-portable hack that should be removed.
2799typedef uint64_t ObjPair;
2800ObjPair MakePair(Object* x, Object* y) {
2801 return reinterpret_cast<uint32_t>(x) |
2802 (reinterpret_cast<ObjPair>(y) << 32);
2803}
2804
2805
2806static Object* Unhole(Object* x, PropertyAttributes attributes) {
2807 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
2808 USE(attributes);
2809 return x->IsTheHole() ? Heap::undefined_value() : x;
2810}
2811
2812
2813static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) {
2814 HandleScope scope;
2815 ASSERT(args.length() == 2);
2816
2817 if (!args[0]->IsContext()) return MakePair(IllegalOperation(), NULL);
2818 Handle<Context> context = args.at<Context>(0);
2819 Handle<String> name(String::cast(args[1]));
2820
2821 int index;
2822 PropertyAttributes attributes;
2823 ContextLookupFlags flags = FOLLOW_CHAINS;
2824 Handle<Object> context_obj =
2825 context->Lookup(name, flags, &index, &attributes);
2826
2827 if (index >= 0) {
2828 if (context_obj->IsContext()) {
2829 // The context is an Execution context, and the "property" we were looking
2830 // for is a local variable in that context. According to ECMA-262, 3rd.,
2831 // 10.1.6 and 10.2.3, the receiver is the global object.
2832 return MakePair(
2833 Unhole(Handle<Context>::cast(context_obj)->get(index), attributes),
2834 Top::context()->global());
2835 } else {
2836 return MakePair(
2837 Unhole(Handle<JSObject>::cast(context_obj)->GetElement(index),
2838 attributes),
2839 *context_obj);
2840 }
2841 }
2842
2843 if (*context_obj != NULL) {
2844 ASSERT(Handle<JSObject>::cast(context_obj)->HasProperty(*name));
2845 // Note: As of 5/29/2008, GetProperty does the "unholing" and so this call
2846 // here is redundant. We left it anyway, to be explicit; also it's not clear
2847 // why GetProperty should do the unholing in the first place.
2848 return MakePair(
2849 Unhole(Handle<JSObject>::cast(context_obj)->GetProperty(*name),
2850 attributes),
2851 *context_obj);
2852 }
2853
2854 if (throw_error) {
2855 // The property doesn't exist - throw exception.
2856 Handle<Object> reference_error =
2857 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
2858 return MakePair(Top::Throw(*reference_error), NULL);
2859 } else {
2860 // The property doesn't exist - return undefined
2861 return MakePair(Heap::undefined_value(), Heap::undefined_value());
2862 }
2863}
2864
2865
2866static ObjPair Runtime_LoadContextSlot(Arguments args) {
2867 return LoadContextSlotHelper(args, true);
2868}
2869
2870
2871static ObjPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
2872 return LoadContextSlotHelper(args, false);
2873}
2874
2875
2876static Object* Runtime_StoreContextSlot(Arguments args) {
2877 HandleScope scope;
2878 ASSERT(args.length() == 3);
2879
2880 Handle<Object> value(args[0]);
2881 CONVERT_ARG_CHECKED(Context, context, 1);
2882 Handle<String> name(String::cast(args[2]));
2883
2884 int index;
2885 PropertyAttributes attributes;
2886 ContextLookupFlags flags = FOLLOW_CHAINS;
2887 Handle<Object> context_obj =
2888 context->Lookup(name, flags, &index, &attributes);
2889
2890 if (index >= 0) {
2891 if (context_obj->IsContext()) {
2892 // Ignore if read_only variable.
2893 if ((attributes & READ_ONLY) == 0) {
2894 Handle<Context>::cast(context_obj)->set(index, *value);
2895 }
2896 } else {
2897 ASSERT((attributes & READ_ONLY) == 0);
2898 Object* result =
2899 Handle<JSObject>::cast(context_obj)->SetElement(index, *value);
2900 USE(result);
2901 ASSERT(!result->IsFailure());
2902 }
2903 return *value;
2904 }
2905
2906 // Slow case: The property is not in a FixedArray context.
2907 // It is either in an JSObject extension context or it was not found.
2908 Handle<JSObject> context_ext;
2909
2910 if (*context_obj != NULL) {
2911 // The property exists in the extension context.
2912 context_ext = Handle<JSObject>::cast(context_obj);
2913 } else {
2914 // The property was not found. It needs to be stored in the global context.
2915 ASSERT(attributes == ABSENT);
2916 attributes = NONE;
2917 context_ext = Handle<JSObject>(Top::context()->global());
2918 }
2919
2920 // Set the property, but ignore if read_only variable.
2921 if ((attributes & READ_ONLY) == 0) {
2922 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
2923 if (set.is_null()) {
2924 // Failure::Exception is converted to a null handle in the
2925 // handle-based methods such as SetProperty. We therefore need
2926 // to convert null handles back to exceptions.
2927 ASSERT(Top::has_pending_exception());
2928 return Failure::Exception();
2929 }
2930 }
2931 return *value;
2932}
2933
2934
2935static Object* Runtime_Throw(Arguments args) {
2936 HandleScope scope;
2937 ASSERT(args.length() == 1);
2938
2939 return Top::Throw(args[0]);
2940}
2941
2942
2943static Object* Runtime_ReThrow(Arguments args) {
2944 HandleScope scope;
2945 ASSERT(args.length() == 1);
2946
2947 return Top::ReThrow(args[0]);
2948}
2949
2950
2951static Object* Runtime_ThrowReferenceError(Arguments args) {
2952 HandleScope scope;
2953 ASSERT(args.length() == 1);
2954
2955 Handle<Object> name(args[0]);
2956 Handle<Object> reference_error =
2957 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
2958 return Top::Throw(*reference_error);
2959}
2960
2961
2962static Object* Runtime_StackOverflow(Arguments args) {
2963 NoHandleAllocation na;
2964 return Top::StackOverflow();
2965}
2966
2967
2968static Object* RuntimePreempt(Arguments args) {
2969 // Clear the preempt request flag.
2970 StackGuard::Continue(PREEMPT);
2971
2972 ContextSwitcher::PreemptionReceived();
2973
2974 {
2975 v8::Unlocker unlocker;
2976 Thread::YieldCPU();
2977 }
2978
2979 return Heap::undefined_value();
2980}
2981
2982
2983static Object* Runtime_DebugBreak(Arguments args) {
kasper.lund44510672008-07-25 07:37:58 +00002984 // Just continue if breaks are disabled or if we fail to load the debugger.
2985 if (Debug::disable_break() || !Debug::Load()) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002986 return args[0];
2987 }
2988
kasper.lund7276f142008-07-30 08:49:36 +00002989 // Don't break in system functions. If the current function is
2990 // either in the builtins object of some context or is in the debug
2991 // context just return with the debug break stack guard active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002992 JavaScriptFrameIterator it;
2993 JavaScriptFrame* frame = it.frame();
2994 Object* fun = frame->function();
2995 if (fun->IsJSFunction()) {
2996 GlobalObject* global = JSFunction::cast(fun)->context()->global();
2997 if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
2998 return args[0];
2999 }
3000 }
3001
3002 // Clear the debug request flag.
3003 StackGuard::Continue(DEBUGBREAK);
3004
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003005 HandleScope scope;
3006 SaveBreakFrame save;
3007 EnterDebuggerContext enter;
3008
kasper.lund7276f142008-07-30 08:49:36 +00003009 // Notify the debug event listeners.
3010 Debugger::OnDebugBreak(Factory::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003011
3012 // Return to continue execution.
3013 return args[0];
3014}
3015
3016
3017static Object* Runtime_StackGuard(Arguments args) {
3018 ASSERT(args.length() == 1);
3019
3020 // First check if this is a real stack overflow.
3021 if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
3022
3023 // If not real stack overflow the stack guard was used to interrupt
3024 // execution for another purpose.
3025 if (StackGuard::IsDebugBreak()) Runtime_DebugBreak(args);
3026 if (StackGuard::IsPreempted()) RuntimePreempt(args);
3027 if (StackGuard::IsInterrupted()) {
3028 // interrupt
3029 StackGuard::Continue(INTERRUPT);
3030 return Top::StackOverflow();
3031 }
3032 return Heap::undefined_value();
3033}
3034
3035
3036// NOTE: These PrintXXX functions are defined for all builds (not just
3037// DEBUG builds) because we may want to be able to trace function
3038// calls in all modes.
3039static void PrintString(String* str) {
3040 // not uncommon to have empty strings
3041 if (str->length() > 0) {
3042 SmartPointer<char> s =
3043 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3044 PrintF("%s", *s);
3045 }
3046}
3047
3048
3049static void PrintObject(Object* obj) {
3050 if (obj->IsSmi()) {
3051 PrintF("%d", Smi::cast(obj)->value());
3052 } else if (obj->IsString() || obj->IsSymbol()) {
3053 PrintString(String::cast(obj));
3054 } else if (obj->IsNumber()) {
3055 PrintF("%g", obj->Number());
3056 } else if (obj->IsFailure()) {
3057 PrintF("<failure>");
3058 } else if (obj->IsUndefined()) {
3059 PrintF("<undefined>");
3060 } else if (obj->IsNull()) {
3061 PrintF("<null>");
3062 } else if (obj->IsTrue()) {
3063 PrintF("<true>");
3064 } else if (obj->IsFalse()) {
3065 PrintF("<false>");
3066 } else {
3067 PrintF("%p", obj);
3068 }
3069}
3070
3071
3072static int StackSize() {
3073 int n = 0;
3074 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3075 return n;
3076}
3077
3078
3079static void PrintTransition(Object* result) {
3080 // indentation
3081 { const int nmax = 80;
3082 int n = StackSize();
3083 if (n <= nmax)
3084 PrintF("%4d:%*s", n, n, "");
3085 else
3086 PrintF("%4d:%*s", n, nmax, "...");
3087 }
3088
3089 if (result == NULL) {
3090 // constructor calls
3091 JavaScriptFrameIterator it;
3092 JavaScriptFrame* frame = it.frame();
3093 if (frame->IsConstructor()) PrintF("new ");
3094 // function name
3095 Object* fun = frame->function();
3096 if (fun->IsJSFunction()) {
3097 PrintObject(JSFunction::cast(fun)->shared()->name());
3098 } else {
3099 PrintObject(fun);
3100 }
3101 // function arguments
3102 // (we are intentionally only printing the actually
3103 // supplied parameters, not all parameters required)
3104 PrintF("(this=");
3105 PrintObject(frame->receiver());
3106 const int length = frame->GetProvidedParametersCount();
3107 for (int i = 0; i < length; i++) {
3108 PrintF(", ");
3109 PrintObject(frame->GetParameter(i));
3110 }
3111 PrintF(") {\n");
3112
3113 } else {
3114 // function result
3115 PrintF("} -> ");
3116 PrintObject(result);
3117 PrintF("\n");
3118 }
3119}
3120
3121
3122static Object* Runtime_TraceEnter(Arguments args) {
3123 NoHandleAllocation ha;
3124 PrintTransition(NULL);
3125 return args[0]; // return TOS
3126}
3127
3128
3129static Object* Runtime_TraceExit(Arguments args) {
3130 NoHandleAllocation ha;
3131 PrintTransition(args[0]);
3132 return args[0]; // return TOS
3133}
3134
3135
3136static Object* Runtime_DebugPrint(Arguments args) {
3137 NoHandleAllocation ha;
3138 ASSERT(args.length() == 1);
3139
3140#ifdef DEBUG
3141 if (args[0]->IsString()) {
3142 // If we have a string, assume it's a code "marker"
3143 // and print some interesting cpu debugging info.
3144 JavaScriptFrameIterator it;
3145 JavaScriptFrame* frame = it.frame();
3146 PrintF("fp = %p, sp = %p, pp = %p: ",
3147 frame->fp(), frame->sp(), frame->pp());
3148 } else {
3149 PrintF("DebugPrint: ");
3150 }
3151 args[0]->Print();
3152#else
3153 PrintF("DebugPrint: %p", args[0]);
3154#endif
3155 PrintF("\n");
3156
3157 return args[0]; // return TOS
3158}
3159
3160
3161static Object* Runtime_DebugTrace(Arguments args) {
3162 ASSERT(args.length() == 1);
3163 NoHandleAllocation ha;
3164 Top::PrintStack();
3165 return args[0]; // return TOS
3166}
3167
3168
mads.s.ager31e71382008-08-13 09:32:07 +00003169static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003170 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003171 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003172
3173 // According to ECMA-262, section 15.9.1, page 117, the precision of
3174 // the number in a Date object representing a particular instant in
3175 // time is milliseconds. Therefore, we floor the result of getting
3176 // the OS time.
3177 double millis = floor(OS::TimeCurrentMillis());
3178 return Heap::NumberFromDouble(millis);
3179}
3180
3181
3182static Object* Runtime_DateParseString(Arguments args) {
3183 HandleScope scope;
3184 ASSERT(args.length() == 1);
3185
3186 CONVERT_CHECKED(String, string_object, args[0]);
3187
3188 Handle<String> str(string_object);
3189 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3190 if (DateParser::Parse(*str, *output)) {
3191 return *Factory::NewJSArrayWithElements(output);
3192 } else {
3193 return *Factory::null_value();
3194 }
3195}
3196
3197
3198static Object* Runtime_DateLocalTimezone(Arguments args) {
3199 NoHandleAllocation ha;
3200 ASSERT(args.length() == 1);
3201
3202 CONVERT_DOUBLE_CHECKED(x, args[0]);
3203 char* zone = OS::LocalTimezone(x);
3204 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3205}
3206
3207
3208static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3209 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003210 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003211
3212 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3213}
3214
3215
3216static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3217 NoHandleAllocation ha;
3218 ASSERT(args.length() == 1);
3219
3220 CONVERT_DOUBLE_CHECKED(x, args[0]);
3221 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3222}
3223
3224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003225static Object* Runtime_NumberIsFinite(Arguments args) {
3226 NoHandleAllocation ha;
3227 ASSERT(args.length() == 1);
3228
3229 CONVERT_DOUBLE_CHECKED(value, args[0]);
3230 Object* result;
3231 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3232 result = Heap::false_value();
3233 } else {
3234 result = Heap::true_value();
3235 }
3236 return result;
3237}
3238
3239
mads.s.ager31e71382008-08-13 09:32:07 +00003240static Object* Runtime_NumberMaxValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003241 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003242 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003243
3244 return Heap::number_max_value();
3245}
3246
3247
mads.s.ager31e71382008-08-13 09:32:07 +00003248static Object* Runtime_NumberMinValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003249 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003250 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003251
3252 return Heap::number_min_value();
3253}
3254
3255
mads.s.ager31e71382008-08-13 09:32:07 +00003256static Object* Runtime_NumberNaN(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003257 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003258 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003259
3260 return Heap::nan_value();
3261}
3262
3263
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003264static Object* EvalContext() {
3265 // The topmost JS frame belongs to the eval function which called
3266 // the CompileString runtime function. We need to unwind one level
3267 // to get to the caller of eval.
3268 StackFrameLocator locator;
3269 JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
3270
kasper.lund44510672008-07-25 07:37:58 +00003271 // TODO(900055): Right now we check if the caller of eval() supports
3272 // eval to determine if it's an aliased eval or not. This may not be
3273 // entirely correct in the unlikely case where a function uses both
3274 // aliased and direct eval calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003275 HandleScope scope;
3276 if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
kasper.lund44510672008-07-25 07:37:58 +00003277 // Aliased eval: Evaluate in the global context of the eval
3278 // function to support aliased, cross environment evals.
3279 return *Top::global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003280 }
3281
3282 // Fetch the caller context from the frame.
3283 Handle<Context> caller(Context::cast(frame->context()));
3284
3285 // Check for eval() invocations that cross environments. Use the
3286 // context from the stack if evaluating in current environment.
3287 Handle<Context> target = Top::global_context();
3288 if (caller->global_context() == *target) return *caller;
3289
3290 // Compute a function closure that captures the calling context. We
3291 // need a function that has trivial scope info, since it is only
3292 // used to hold the context chain together.
3293 Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
3294 Factory::undefined_value());
3295 closure->set_context(*caller);
3296
3297 // Create a new adaptor context that has the target environment as
3298 // the extension object. This enables the evaluated code to see both
3299 // the current context with locals and everything and to see global
3300 // variables declared in the target global object. Furthermore, any
3301 // properties introduced with 'var' will be added to the target
3302 // global object because it is the extension object.
3303 Handle<Context> adaptor =
3304 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
3305 adaptor->set_extension(target->global());
3306 return *adaptor;
3307}
3308
3309
3310static Object* Runtime_EvalReceiver(Arguments args) {
3311 StackFrameLocator locator;
3312 return locator.FindJavaScriptFrame(1)->receiver();
3313}
3314
3315
3316static Object* Runtime_CompileString(Arguments args) {
3317 HandleScope scope;
3318 ASSERT(args.length() == 2);
3319 bool contextual = args[1]->IsTrue();
3320 RUNTIME_ASSERT(contextual || args[1]->IsFalse());
3321
3322 // Compute the eval context.
3323 Handle<Context> context;
3324 if (contextual) {
3325 // Get eval context. May not be available if we are calling eval
3326 // through an alias, and the corresponding frame doesn't have a
3327 // proper eval context set up.
3328 Object* eval_context = EvalContext();
3329 if (eval_context->IsFailure()) return eval_context;
3330 context = Handle<Context>(Context::cast(eval_context));
3331 } else {
3332 context = Handle<Context>(Top::context()->global_context());
3333 }
3334
3335 // Compile eval() source.
3336 Handle<String> source(String::cast(args[0]));
3337 Handle<JSFunction> boilerplate =
3338 Compiler::CompileEval(context->IsGlobalContext(), source);
3339 if (boilerplate.is_null()) return Failure::Exception();
3340 Handle<JSFunction> fun =
3341 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3342 return *fun;
3343}
3344
3345
3346static Object* Runtime_CompileScript(Arguments args) {
3347 HandleScope scope;
3348 ASSERT(args.length() == 4);
3349
3350 CONVERT_ARG_CHECKED(String, source, 0);
3351 CONVERT_ARG_CHECKED(String, script, 1);
3352 CONVERT_CHECKED(Smi, line_attrs, args[2]);
3353 int line = line_attrs->value();
3354 CONVERT_CHECKED(Smi, col_attrs, args[3]);
3355 int col = col_attrs->value();
3356 Handle<JSFunction> boilerplate =
3357 Compiler::Compile(source, script, line, col, NULL, NULL);
3358 if (boilerplate.is_null()) return Failure::Exception();
3359 Handle<JSFunction> fun =
3360 Factory::NewFunctionFromBoilerplate(boilerplate,
3361 Handle<Context>(Top::context()));
3362 return *fun;
3363}
3364
3365
3366static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
3367 // This utility adjusts the property attributes for newly created Function
3368 // object ("new Function(...)") by changing the map.
3369 // All it does is changing the prototype property to enumerable
3370 // as specified in ECMA262, 15.3.5.2.
3371 HandleScope scope;
3372 ASSERT(args.length() == 1);
3373 CONVERT_ARG_CHECKED(JSFunction, func, 0);
3374 ASSERT(func->map()->instance_type() ==
3375 Top::function_instance_map()->instance_type());
3376 ASSERT(func->map()->instance_size() ==
3377 Top::function_instance_map()->instance_size());
3378 func->set_map(*Top::function_instance_map());
3379 return *func;
3380}
3381
3382
3383// This will not allocate (flatten the string), but it may run
3384// very slowly for very deeply nested ConsStrings. For debugging use only.
3385static Object* Runtime_GlobalPrint(Arguments args) {
3386 NoHandleAllocation ha;
3387 ASSERT(args.length() == 1);
3388
3389 CONVERT_CHECKED(String, string, args[0]);
3390 StringInputBuffer buffer(string);
3391 while (buffer.has_more()) {
3392 uint16_t character = buffer.GetNext();
3393 PrintF("%c", character);
3394 }
3395 return string;
3396}
3397
3398
3399static Object* Runtime_RemoveArrayHoles(Arguments args) {
3400 ASSERT(args.length() == 1);
3401 // Ignore the case if this is not a JSArray.
3402 if (!args[0]->IsJSArray()) return args[0];
3403 return JSArray::cast(args[0])->RemoveHoles();
3404}
3405
3406
3407// Move contents of argument 0 (an array) to argument 1 (an array)
3408static Object* Runtime_MoveArrayContents(Arguments args) {
3409 ASSERT(args.length() == 2);
3410 CONVERT_CHECKED(JSArray, from, args[0]);
3411 CONVERT_CHECKED(JSArray, to, args[1]);
3412 to->SetContent(FixedArray::cast(from->elements()));
3413 to->set_length(from->length());
3414 from->SetContent(Heap::empty_fixed_array());
3415 from->set_length(0);
3416 return to;
3417}
3418
3419
3420// How many elements does this array have?
3421static Object* Runtime_EstimateNumberOfElements(Arguments args) {
3422 ASSERT(args.length() == 1);
3423 CONVERT_CHECKED(JSArray, array, args[0]);
3424 HeapObject* elements = array->elements();
3425 if (elements->IsDictionary()) {
3426 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
3427 } else {
3428 return array->length();
3429 }
3430}
3431
3432
3433// Returns an array that tells you where in the [0, length) interval an array
3434// might have elements. Can either return keys or intervals. Keys can have
3435// gaps in (undefined). Intervals can also span over some undefined keys.
3436static Object* Runtime_GetArrayKeys(Arguments args) {
3437 ASSERT(args.length() == 2);
3438 HandleScope scope;
3439 CONVERT_CHECKED(JSArray, raw_array, args[0]);
3440 Handle<JSArray> array(raw_array);
3441 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
3442 HeapObject* elements = array->elements();
3443 if (elements->IsDictionary()) {
3444 // Create an array and get all the keys into it, then remove all the
3445 // keys that are not integers in the range 0 to length-1.
3446 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
3447 int keys_length = keys->length();
3448 for (int i = 0; i < keys_length; i++) {
3449 Object* key = keys->get(i);
3450 uint32_t index;
3451 if (!Array::IndexFromObject(key, &index) || index >= length) {
3452 // Zap invalid keys.
3453 keys->set_undefined(i);
3454 }
3455 }
3456 return *Factory::NewJSArrayWithElements(keys);
3457 } else {
3458 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
3459 // -1 means start of array.
3460 single_interval->set(0, Smi::FromInt(-1));
3461 Handle<Object> length_object =
3462 Factory::NewNumber(static_cast<double>(length));
3463 single_interval->set(1, *length_object);
3464 return *Factory::NewJSArrayWithElements(single_interval);
3465 }
3466}
3467
3468
3469// DefineAccessor takes an optional final argument which is the
3470// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
3471// to the way accessors are implemented, it is set for both the getter
3472// and setter on the first call to DefineAccessor and ignored on
3473// subsequent calls.
3474static Object* Runtime_DefineAccessor(Arguments args) {
3475 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
3476 // Compute attributes.
3477 PropertyAttributes attributes = NONE;
3478 if (args.length() == 5) {
3479 CONVERT_CHECKED(Smi, attrs, args[4]);
3480 int value = attrs->value();
3481 // Only attribute bits should be set.
3482 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3483 attributes = static_cast<PropertyAttributes>(value);
3484 }
3485
3486 CONVERT_CHECKED(JSObject, obj, args[0]);
3487 CONVERT_CHECKED(String, name, args[1]);
3488 CONVERT_CHECKED(Smi, flag, args[2]);
3489 CONVERT_CHECKED(JSFunction, fun, args[3]);
3490 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
3491}
3492
3493
3494static Object* Runtime_LookupAccessor(Arguments args) {
3495 ASSERT(args.length() == 3);
3496 CONVERT_CHECKED(JSObject, obj, args[0]);
3497 CONVERT_CHECKED(String, name, args[1]);
3498 CONVERT_CHECKED(Smi, flag, args[2]);
3499 return obj->LookupAccessor(name, flag->value() == 0);
3500}
3501
3502
3503// Helper functions for wrapping and unwrapping stack frame ids.
3504static Smi* WrapFrameId(StackFrame::Id id) {
3505 ASSERT(IsAligned(OffsetFrom(id), 4));
3506 return Smi::FromInt(id >> 2);
3507}
3508
3509
3510static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
3511 return static_cast<StackFrame::Id>(wrapped->value() << 2);
3512}
3513
3514
3515// Adds a JavaScript function as a debug event listener.
3516// args[0]: debug event listener function
3517// args[1]: object supplied during callback
3518static Object* Runtime_AddDebugEventListener(Arguments args) {
3519 ASSERT(args.length() == 2);
3520 // Convert the parameters to API objects to call the API function for adding
3521 // a JavaScript function as debug event listener.
3522 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
3523 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
3524 v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
3525 v8::Debug::AddDebugEventListener(fun, data);
3526
3527 return Heap::undefined_value();
3528}
3529
3530
3531// Removes a JavaScript function debug event listener.
3532// args[0]: debug event listener function
3533static Object* Runtime_RemoveDebugEventListener(Arguments args) {
3534 ASSERT(args.length() == 1);
3535 // Convert the parameter to an API object to call the API function for
3536 // removing a JavaScript function debug event listener.
3537 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
3538 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
3539 v8::Debug::RemoveDebugEventListener(fun);
3540
3541 return Heap::undefined_value();
3542}
3543
3544
3545static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00003546 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 StackGuard::DebugBreak();
3548 return Heap::undefined_value();
3549}
3550
3551
3552static Object* DebugLookupResultValue(LookupResult* result) {
3553 Object* value;
3554 switch (result->type()) {
3555 case NORMAL: {
3556 Dictionary* dict =
3557 JSObject::cast(result->holder())->property_dictionary();
3558 value = dict->ValueAt(result->GetDictionaryEntry());
3559 if (value->IsTheHole()) {
3560 return Heap::undefined_value();
3561 }
3562 return value;
3563 }
3564 case FIELD:
3565 value =
3566 JSObject::cast(
3567 result->holder())->properties()->get(result->GetFieldIndex());
3568 if (value->IsTheHole()) {
3569 return Heap::undefined_value();
3570 }
3571 return value;
3572 case CONSTANT_FUNCTION:
3573 return result->GetConstantFunction();
3574 case CALLBACKS:
3575 return Heap::undefined_value();
3576 case MAP_TRANSITION:
3577 return Heap::undefined_value();
3578 case INTERCEPTOR:
3579 return Heap::undefined_value();
3580 default:
3581 UNREACHABLE();
3582 }
3583 return Heap::undefined_value();
3584}
3585
3586
3587static Object* Runtime_DebugGetLocalPropertyDetails(Arguments args) {
3588 HandleScope scope;
3589
3590 ASSERT(args.length() == 2);
3591
3592 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3593 CONVERT_ARG_CHECKED(String, name, 1);
3594
3595 // Check if the name is trivially convertible to an index and get the element
3596 // if so.
3597 uint32_t index;
3598 if (name->AsArrayIndex(&index)) {
3599 Handle<FixedArray> details = Factory::NewFixedArray(2);
3600 details->set(0, Runtime::GetElementOrCharAt(obj, index));
3601 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
3602 return *Factory::NewJSArrayWithElements(details);
3603 }
3604
3605 // Perform standard local lookup on the object.
3606 LookupResult result;
3607 obj->LocalLookup(*name, &result);
3608 if (result.IsProperty()) {
3609 Handle<Object> value(DebugLookupResultValue(&result));
3610 Handle<FixedArray> details = Factory::NewFixedArray(2);
3611 details->set(0, *value);
3612 details->set(1, result.GetPropertyDetails().AsSmi());
3613 return *Factory::NewJSArrayWithElements(details);
3614 }
3615 return Heap::undefined_value();
3616}
3617
3618
3619static Object* Runtime_DebugGetProperty(Arguments args) {
3620 HandleScope scope;
3621
3622 ASSERT(args.length() == 2);
3623
3624 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3625 CONVERT_ARG_CHECKED(String, name, 1);
3626
3627 LookupResult result;
3628 obj->Lookup(*name, &result);
3629 if (result.IsProperty()) {
3630 return DebugLookupResultValue(&result);
3631 }
3632 return Heap::undefined_value();
3633}
3634
3635
3636// Return the names of the local named properties.
3637// args[0]: object
3638static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
3639 HandleScope scope;
3640 ASSERT(args.length() == 1);
3641 if (!args[0]->IsJSObject()) {
3642 return Heap::undefined_value();
3643 }
3644 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3645
3646 int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3647 Handle<FixedArray> names = Factory::NewFixedArray(n);
3648 obj->GetLocalPropertyNames(*names);
3649 return *Factory::NewJSArrayWithElements(names);
3650}
3651
3652
3653// Return the names of the local indexed properties.
3654// args[0]: object
3655static Object* Runtime_DebugLocalElementNames(Arguments args) {
3656 HandleScope scope;
3657 ASSERT(args.length() == 1);
3658 if (!args[0]->IsJSObject()) {
3659 return Heap::undefined_value();
3660 }
3661 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3662
3663 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
3664 Handle<FixedArray> names = Factory::NewFixedArray(n);
3665 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
3666 return *Factory::NewJSArrayWithElements(names);
3667}
3668
3669
3670// Return the property type calculated from the property details.
3671// args[0]: smi with property details.
3672static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
3673 ASSERT(args.length() == 1);
3674 CONVERT_CHECKED(Smi, details, args[0]);
3675 PropertyType type = PropertyDetails(details).type();
3676 return Smi::FromInt(static_cast<int>(type));
3677}
3678
3679
3680// Return the property attribute calculated from the property details.
3681// args[0]: smi with property details.
3682static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
3683 ASSERT(args.length() == 1);
3684 CONVERT_CHECKED(Smi, details, args[0]);
3685 PropertyAttributes attributes = PropertyDetails(details).attributes();
3686 return Smi::FromInt(static_cast<int>(attributes));
3687}
3688
3689
3690// Return the property insertion index calculated from the property details.
3691// args[0]: smi with property details.
3692static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
3693 ASSERT(args.length() == 1);
3694 CONVERT_CHECKED(Smi, details, args[0]);
3695 int index = PropertyDetails(details).index();
3696 return Smi::FromInt(index);
3697}
3698
3699
3700// Return information on whether an object has a named or indexed interceptor.
3701// args[0]: object
3702static Object* Runtime_DebugInterceptorInfo(Arguments args) {
3703 HandleScope scope;
3704 ASSERT(args.length() == 1);
3705 if (!args[0]->IsJSObject()) {
3706 return Smi::FromInt(0);
3707 }
3708 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3709
3710 int result = 0;
3711 if (obj->HasNamedInterceptor()) result |= 2;
3712 if (obj->HasIndexedInterceptor()) result |= 1;
3713
3714 return Smi::FromInt(result);
3715}
3716
3717
3718// Return property names from named interceptor.
3719// args[0]: object
3720static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
3721 HandleScope scope;
3722 ASSERT(args.length() == 1);
3723 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3724 RUNTIME_ASSERT(obj->HasNamedInterceptor());
3725
3726 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
3727 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
3728 return Heap::undefined_value();
3729}
3730
3731
3732// Return element names from indexed interceptor.
3733// args[0]: object
3734static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
3735 HandleScope scope;
3736 ASSERT(args.length() == 1);
3737 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3738 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
3739
3740 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
3741 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
3742 return Heap::undefined_value();
3743}
3744
3745
3746// Return property value from named interceptor.
3747// args[0]: object
3748// args[1]: property name
3749static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
3750 HandleScope scope;
3751 ASSERT(args.length() == 2);
3752 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3753 RUNTIME_ASSERT(obj->HasNamedInterceptor());
3754 CONVERT_ARG_CHECKED(String, name, 1);
3755
3756 PropertyAttributes attributes;
3757 Object* result = obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
3758 return result;
3759}
3760
3761
3762// Return element value from indexed interceptor.
3763// args[0]: object
3764// args[1]: index
3765static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
3766 HandleScope scope;
3767 ASSERT(args.length() == 2);
3768 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3769 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
3770 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
3771
3772 Object* result = obj->GetElementWithInterceptor(*obj, index);
3773 return result;
3774}
3775
3776
3777static Object* Runtime_CheckExecutionState(Arguments args) {
3778 ASSERT(args.length() >= 1);
3779 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
3780 // Check that the break id is valid and that there is a valid frame
3781 // where execution is broken.
3782 if (break_id != Top::break_id() ||
3783 Top::break_frame_id() == StackFrame::NO_ID) {
3784 return Top::Throw(Heap::illegal_execution_state_symbol());
3785 }
3786
3787 return Heap::true_value();
3788}
3789
3790
3791static Object* Runtime_GetFrameCount(Arguments args) {
3792 HandleScope scope;
3793 ASSERT(args.length() == 1);
3794
3795 // Check arguments.
3796 Object* result = Runtime_CheckExecutionState(args);
3797 if (result->IsFailure()) return result;
3798
3799 // Count all frames which are relevant to debugging stack trace.
3800 int n = 0;
3801 StackFrame::Id id = Top::break_frame_id();
3802 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
3803 return Smi::FromInt(n);
3804}
3805
3806
3807static const int kFrameDetailsFrameIdIndex = 0;
3808static const int kFrameDetailsReceiverIndex = 1;
3809static const int kFrameDetailsFunctionIndex = 2;
3810static const int kFrameDetailsArgumentCountIndex = 3;
3811static const int kFrameDetailsLocalCountIndex = 4;
3812static const int kFrameDetailsSourcePositionIndex = 5;
3813static const int kFrameDetailsConstructCallIndex = 6;
3814static const int kFrameDetailsDebuggerFrameIndex = 7;
3815static const int kFrameDetailsFirstDynamicIndex = 8;
3816
3817// Return an array with frame details
3818// args[0]: number: break id
3819// args[1]: number: frame index
3820//
3821// The array returned contains the following information:
3822// 0: Frame id
3823// 1: Receiver
3824// 2: Function
3825// 3: Argument count
3826// 4: Local count
3827// 5: Source position
3828// 6: Constructor call
3829// 7: Debugger frame
3830// Arguments name, value
3831// Locals name, value
3832static Object* Runtime_GetFrameDetails(Arguments args) {
3833 HandleScope scope;
3834 ASSERT(args.length() == 2);
3835
3836 // Check arguments.
3837 Object* result = Runtime_CheckExecutionState(args);
3838 if (result->IsFailure()) return result;
3839 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
3840
3841 // Find the relevant frame with the requested index.
3842 StackFrame::Id id = Top::break_frame_id();
3843 int count = 0;
3844 JavaScriptFrameIterator it(id);
3845 for (; !it.done(); it.Advance()) {
3846 if (count == index) break;
3847 count++;
3848 }
3849 if (it.done()) return Heap::undefined_value();
3850
3851 // Traverse the saved contexts chain to find the active context for the
3852 // selected frame.
3853 SaveContext* save = Top::save_context();
3854 while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
3855 save = save->prev();
3856 }
3857
3858 // Get the frame id.
3859 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
3860
3861 // Find source position.
3862 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
3863
3864 // Check for constructor frame.
3865 bool constructor = it.frame()->IsConstructor();
3866
3867 // Get code and read scope info from it for local variable information.
3868 Handle<Code> code(it.frame()->FindCode());
3869 ScopeInfo<> info(*code);
3870
3871 // Get the context.
3872 Handle<Context> context(Context::cast(it.frame()->context()));
3873
3874 // Get the locals names and values into a temporary array.
3875 //
3876 // TODO(1240907): Hide compiler-introduced stack variables
3877 // (e.g. .result)? For users of the debugger, they will probably be
3878 // confusing.
3879 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
3880 for (int i = 0; i < info.NumberOfLocals(); i++) {
3881 // Name of the local.
3882 locals->set(i * 2, *info.LocalName(i));
3883
3884 // Fetch the value of the local - either from the stack or from a
3885 // heap-allocated context.
3886 if (i < info.number_of_stack_slots()) {
3887 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
3888 } else {
3889 Handle<String> name = info.LocalName(i);
3890 // Traverse the context chain to the function context as all local
3891 // variables stored in the context will be on the function context.
3892 while (context->previous() != NULL) {
3893 context = Handle<Context>(context->previous());
3894 }
3895 ASSERT(context->is_function_context());
3896 locals->set(i * 2 + 1,
3897 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
3898 NULL)));
3899 }
3900 }
3901
3902 // Now advance to the arguments adapter frame (if any). If contains all
3903 // the provided parameters and
3904
3905 // Now advance to the arguments adapter frame (if any). It contains all
3906 // the provided parameters whereas the function frame always have the number
3907 // of arguments matching the functions parameters. The rest of the
3908 // information (except for what is collected above) is the same.
3909 it.AdvanceToArgumentsFrame();
3910
3911 // Find the number of arguments to fill. At least fill the number of
3912 // parameters for the function and fill more if more parameters are provided.
3913 int argument_count = info.number_of_parameters();
3914 if (argument_count < it.frame()->GetProvidedParametersCount()) {
3915 argument_count = it.frame()->GetProvidedParametersCount();
3916 }
3917
3918 // Calculate the size of the result.
3919 int details_size = kFrameDetailsFirstDynamicIndex +
3920 2 * (argument_count + info.NumberOfLocals());
3921 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
3922
3923 // Add the frame id.
3924 details->set(kFrameDetailsFrameIdIndex, *frame_id);
3925
3926 // Add the function (same as in function frame).
3927 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
3928
3929 // Add the arguments count.
3930 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
3931
3932 // Add the locals count
3933 details->set(kFrameDetailsLocalCountIndex,
3934 Smi::FromInt(info.NumberOfLocals()));
3935
3936 // Add the source position.
3937 if (position != kNoPosition) {
3938 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
3939 } else {
3940 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
3941 }
3942
3943 // Add the constructor information.
3944 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
3945
3946 // Add information on whether this frame is invoked in the debugger context.
3947 details->set(kFrameDetailsDebuggerFrameIndex,
3948 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
3949
3950 // Fill the dynamic part.
3951 int details_index = kFrameDetailsFirstDynamicIndex;
3952
3953 // Add arguments name and value.
3954 for (int i = 0; i < argument_count; i++) {
3955 // Name of the argument.
3956 if (i < info.number_of_parameters()) {
3957 details->set(details_index++, *info.parameter_name(i));
3958 } else {
3959 details->set(details_index++, Heap::undefined_value());
3960 }
3961
3962 // Parameter value.
3963 if (i < it.frame()->GetProvidedParametersCount()) {
3964 details->set(details_index++, it.frame()->GetParameter(i));
3965 } else {
3966 details->set(details_index++, Heap::undefined_value());
3967 }
3968 }
3969
3970 // Add locals name and value from the temporary copy from the function frame.
3971 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
3972 details->set(details_index++, locals->get(i));
3973 }
3974
3975 // Add the receiver (same as in function frame).
3976 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
3977 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
3978 Handle<Object> receiver(it.frame()->receiver());
3979 if (!receiver->IsJSObject()) {
3980 // If the receiver is NOT a JSObject we have hit an optimization
3981 // where a value object is not converted into a wrapped JS objects.
3982 // To hide this optimization from the debugger, we wrap the receiver
3983 // by creating correct wrapper object based on the calling frame's
3984 // global context.
3985 it.Advance();
3986 Handle<Context> calling_frames_global_context(
3987 Context::cast(Context::cast(it.frame()->context())->global_context()));
3988 receiver = Factory::ToObject(receiver, calling_frames_global_context);
3989 }
3990 details->set(kFrameDetailsReceiverIndex, *receiver);
3991
3992 ASSERT_EQ(details_size, details_index);
3993 return *Factory::NewJSArrayWithElements(details);
3994}
3995
3996
3997static Object* Runtime_GetCFrames(Arguments args) {
3998 HandleScope scope;
3999 ASSERT(args.length() == 1);
4000 Object* result = Runtime_CheckExecutionState(args);
4001 if (result->IsFailure()) return result;
4002
4003 static const int kMaxCFramesSize = 200;
4004 OS::StackFrame frames[kMaxCFramesSize];
4005 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
4006 if (frames_count == OS::kStackWalkError) {
4007 return Heap::undefined_value();
4008 }
4009
4010 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
4011 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
4012 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
4013 for (int i = 0; i < frames_count; i++) {
4014 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
4015 frame_value->SetProperty(
4016 *address_str,
4017 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
4018 NONE);
4019
4020 // Get the stack walk text for this frame.
4021 Handle<String> frame_text;
4022 if (strlen(frames[i].text) > 0) {
4023 Vector<const char> str(frames[i].text, strlen(frames[i].text));
4024 frame_text = Factory::NewStringFromAscii(str);
4025 }
4026
4027 if (!frame_text.is_null()) {
4028 frame_value->SetProperty(*text_str, *frame_text, NONE);
4029 }
4030
4031 frames_array->set(i, *frame_value);
4032 }
4033 return *Factory::NewJSArrayWithElements(frames_array);
4034}
4035
4036
4037static Object* Runtime_GetBreakLocations(Arguments args) {
4038 HandleScope scope;
4039 ASSERT(args.length() == 1);
4040
4041 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4042 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4043 // Find the number of break points
4044 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
4045 if (break_locations->IsUndefined()) return Heap::undefined_value();
4046 // Return array as JS array
4047 return *Factory::NewJSArrayWithElements(
4048 Handle<FixedArray>::cast(break_locations));
4049}
4050
4051
4052// Set a break point in a function
4053// args[0]: function
4054// args[1]: number: break source position (within the function source)
4055// args[2]: number: break point object
4056static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
4057 HandleScope scope;
4058 ASSERT(args.length() == 3);
4059 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4060 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4061 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4062 RUNTIME_ASSERT(source_position >= 0);
4063 Handle<Object> break_point_object_arg = args.at<Object>(2);
4064
4065 // Set break point.
4066 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
4067
4068 return Heap::undefined_value();
4069}
4070
4071
4072static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
4073 int position) {
4074 // Iterate the heap looking for SharedFunctionInfo generated from the
4075 // script. The inner most SharedFunctionInfo containing the source position
4076 // for the requested break point is found.
4077 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
4078 // which is found is not compiled it is compiled and the heap is iterated
4079 // again as the compilation might create inner functions from the newly
4080 // compiled function and the actual requested break point might be in one of
4081 // these functions.
4082 bool done = false;
4083 // The current candidate for the source position:
4084 int target_start_position = kNoPosition;
4085 Handle<SharedFunctionInfo> target;
4086 // The current candidate for the last function in script:
4087 Handle<SharedFunctionInfo> last;
4088 while (!done) {
4089 HeapIterator iterator;
4090 while (iterator.has_next()) {
4091 HeapObject* obj = iterator.next();
4092 ASSERT(obj != NULL);
4093 if (obj->IsSharedFunctionInfo()) {
4094 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
4095 if (shared->script() == *script) {
4096 // If the SharedFunctionInfo found has the requested script data and
4097 // contains the source position it is a candidate.
4098 int start_position = shared->function_token_position();
4099 if (start_position == kNoPosition) {
4100 start_position = shared->start_position();
4101 }
4102 if (start_position <= position &&
4103 position <= shared->end_position()) {
4104 // If there is no candidate or this function is within the currrent
4105 // candidate this is the new candidate.
4106 if (target.is_null()) {
4107 target_start_position = start_position;
4108 target = shared;
4109 } else {
4110 if (target_start_position < start_position &&
4111 shared->end_position() < target->end_position()) {
4112 target_start_position = start_position;
4113 target = shared;
4114 }
4115 }
4116 }
4117
4118 // Keep track of the last function in the script.
4119 if (last.is_null() ||
4120 shared->end_position() > last->start_position()) {
4121 last = shared;
4122 }
4123 }
4124 }
4125 }
4126
4127 // Make sure some candidate is selected.
4128 if (target.is_null()) {
4129 if (!last.is_null()) {
4130 // Position after the last function - use last.
4131 target = last;
4132 } else {
4133 // Unable to find function - possibly script without any function.
4134 return Heap::undefined_value();
4135 }
4136 }
4137
4138 // If the candidate found is compiled we are done. NOTE: when lazy
4139 // compilation of inner functions is introduced some additional checking
4140 // needs to be done here to compile inner functions.
4141 done = target->is_compiled();
4142 if (!done) {
4143 // If the candidate is not compiled compile it to reveal any inner
4144 // functions which might contain the requested source position.
4145 CompileLazyShared(target, KEEP_EXCEPTION);
4146 }
4147 }
4148
4149 return *target;
4150}
4151
4152
4153// Change the state of a break point in a script. NOTE: Regarding performance
4154// see the NOTE for GetScriptFromScriptData.
4155// args[0]: script to set break point in
4156// args[1]: number: break source position (within the script source)
4157// args[2]: number: break point object
4158static Object* Runtime_SetScriptBreakPoint(Arguments args) {
4159 HandleScope scope;
4160 ASSERT(args.length() == 3);
4161 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
4162 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4163 RUNTIME_ASSERT(source_position >= 0);
4164 Handle<Object> break_point_object_arg = args.at<Object>(2);
4165
4166 // Get the script from the script wrapper.
4167 RUNTIME_ASSERT(wrapper->value()->IsScript());
4168 Handle<Script> script(Script::cast(wrapper->value()));
4169
4170 Object* result = FindSharedFunctionInfoInScript(script, source_position);
4171 if (!result->IsUndefined()) {
4172 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
4173 // Find position within function. The script position might be before the
4174 // source position of the first function.
4175 int position;
4176 if (shared->start_position() > source_position) {
4177 position = 0;
4178 } else {
4179 position = source_position - shared->start_position();
4180 }
4181 Debug::SetBreakPoint(shared, position, break_point_object_arg);
4182 }
4183 return Heap::undefined_value();
4184}
4185
4186
4187// Clear a break point
4188// args[0]: number: break point object
4189static Object* Runtime_ClearBreakPoint(Arguments args) {
4190 HandleScope scope;
4191 ASSERT(args.length() == 1);
4192 Handle<Object> break_point_object_arg = args.at<Object>(0);
4193
4194 // Clear break point.
4195 Debug::ClearBreakPoint(break_point_object_arg);
4196
4197 return Heap::undefined_value();
4198}
4199
4200
4201// Change the state of break on exceptions
4202// args[0]: boolean indicating uncaught exceptions
4203// args[1]: boolean indicating on/off
4204static Object* Runtime_ChangeBreakOnException(Arguments args) {
4205 HandleScope scope;
4206 ASSERT(args.length() == 2);
4207 ASSERT(args[0]->IsNumber());
4208 ASSERT(args[1]->IsBoolean());
4209
4210 // Update break point state
4211 ExceptionBreakType type =
4212 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
4213 bool enable = args[1]->ToBoolean()->IsTrue();
4214 Debug::ChangeBreakOnException(type, enable);
4215 return Heap::undefined_value();
4216}
4217
4218
4219// Prepare for stepping
4220// args[0]: break id for checking execution state
4221// args[1]: step action from the enumeration StepAction
4222// args[2]: number of times to perform the step
4223static Object* Runtime_PrepareStep(Arguments args) {
4224 HandleScope scope;
4225 ASSERT(args.length() == 3);
4226 // Check arguments.
4227 Object* check_result = Runtime_CheckExecutionState(args);
4228 if (check_result->IsFailure()) return check_result;
4229 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
4230 return Top::Throw(Heap::illegal_argument_symbol());
4231 }
4232
4233 // Get the step action and check validity.
4234 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
4235 if (step_action != StepIn &&
4236 step_action != StepNext &&
4237 step_action != StepOut &&
4238 step_action != StepInMin &&
4239 step_action != StepMin) {
4240 return Top::Throw(Heap::illegal_argument_symbol());
4241 }
4242
4243 // Get the number of steps.
4244 int step_count = NumberToInt32(args[2]);
4245 if (step_count < 1) {
4246 return Top::Throw(Heap::illegal_argument_symbol());
4247 }
4248
4249 // Prepare step.
4250 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
4251 return Heap::undefined_value();
4252}
4253
4254
4255// Clear all stepping set by PrepareStep.
4256static Object* Runtime_ClearStepping(Arguments args) {
4257 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004258 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004259 Debug::ClearStepping();
4260 return Heap::undefined_value();
4261}
4262
4263
4264// Creates a copy of the with context chain. The copy of the context chain is
4265// is linked to the function context supplied.
4266static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
4267 Handle<Context> function_context) {
4268 // At the bottom of the chain. Return the function context to link to.
4269 if (context_chain->is_function_context()) {
4270 return function_context;
4271 }
4272
4273 // Recursively copy the with contexts.
4274 Handle<Context> previous(context_chain->previous());
4275 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
4276 return Factory::NewWithContext(
4277 CopyWithContextChain(function_context, previous), extension);
4278}
4279
4280
4281// Helper function to find or create the arguments object for
4282// Runtime_DebugEvaluate.
4283static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
4284 Handle<JSFunction> function,
4285 Handle<Code> code,
4286 const ScopeInfo<>* sinfo,
4287 Handle<Context> function_context) {
4288 // Try to find the value of 'arguments' to pass as parameter. If it is not
4289 // found (that is the debugged function does not reference 'arguments' and
4290 // does not support eval) then create an 'arguments' object.
4291 int index;
4292 if (sinfo->number_of_stack_slots() > 0) {
4293 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
4294 if (index != -1) {
4295 return Handle<Object>(frame->GetExpression(index));
4296 }
4297 }
4298
4299 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
4300 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
4301 NULL);
4302 if (index != -1) {
4303 return Handle<Object>(function_context->get(index));
4304 }
4305 }
4306
4307 const int length = frame->GetProvidedParametersCount();
4308 Handle<Object> arguments = Factory::NewArgumentsObject(function, length);
4309 FixedArray* array = FixedArray::cast(JSObject::cast(*arguments)->elements());
4310 ASSERT(array->length() == length);
4311 for (int i = 0; i < length; i++) {
4312 array->set(i, frame->GetParameter(i));
4313 }
4314 return arguments;
4315}
4316
4317
4318// Evaluate a piece of JavaScript in the context of a stack frame for
4319// debugging. This is acomplished by creating a new context which in its
4320// extension part has all the parameters and locals of the function on the
4321// stack frame. A function which calls eval with the code to evaluate is then
4322// compiled in this context and called in this context. As this context
4323// replaces the context of the function on the stack frame a new (empty)
4324// function is created as well to be used as the closure for the context.
4325// This function and the context acts as replacements for the function on the
4326// stack frame presenting the same view of the values of parameters and
4327// local variables as if the piece of JavaScript was evaluated at the point
4328// where the function on the stack frame is currently stopped.
4329static Object* Runtime_DebugEvaluate(Arguments args) {
4330 HandleScope scope;
4331
4332 // Check the execution state and decode arguments frame and source to be
4333 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004334 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004335 Object* check_result = Runtime_CheckExecutionState(args);
4336 if (check_result->IsFailure()) return check_result;
4337 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
4338 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004339 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
4340
4341 // Handle the processing of break.
4342 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004343
4344 // Get the frame where the debugging is performed.
4345 StackFrame::Id id = UnwrapFrameId(wrapped_id);
4346 JavaScriptFrameIterator it(id);
4347 JavaScriptFrame* frame = it.frame();
4348 Handle<JSFunction> function(JSFunction::cast(frame->function()));
4349 Handle<Code> code(function->code());
4350 ScopeInfo<> sinfo(*code);
4351
4352 // Traverse the saved contexts chain to find the active context for the
4353 // selected frame.
4354 SaveContext* save = Top::save_context();
4355 while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
4356 save = save->prev();
4357 }
4358 ASSERT(save != NULL);
4359 SaveContext savex;
4360 Top::set_context(*(save->context()));
4361 Top::set_security_context(*(save->security_context()));
4362
4363 // Create the (empty) function replacing the function on the stack frame for
4364 // the purpose of evaluating in the context created below. It is important
4365 // that this function does not describe any parameters and local variables
4366 // in the context. If it does then this will cause problems with the lookup
4367 // in Context::Lookup, where context slots for parameters and local variables
4368 // are looked at before the extension object.
4369 Handle<JSFunction> go_between =
4370 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
4371 go_between->set_context(function->context());
4372#ifdef DEBUG
4373 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
4374 ASSERT(go_between_sinfo.number_of_parameters() == 0);
4375 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
4376#endif
4377
4378 // Allocate and initialize a context extension object with all the
4379 // arguments, stack locals heap locals and extension properties of the
4380 // debugged function.
4381 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
4382 // First fill all parameters to the context extension.
4383 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
4384 SetProperty(context_ext,
4385 sinfo.parameter_name(i),
4386 Handle<Object>(frame->GetParameter(i)), NONE);
4387 }
4388 // Second fill all stack locals to the context extension.
4389 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
4390 SetProperty(context_ext,
4391 sinfo.stack_slot_name(i),
4392 Handle<Object>(frame->GetExpression(i)), NONE);
4393 }
4394 // Third fill all context locals to the context extension.
4395 Handle<Context> frame_context(Context::cast(frame->context()));
4396 Handle<Context> function_context(frame_context->fcontext());
4397 for (int i = Context::MIN_CONTEXT_SLOTS;
4398 i < sinfo.number_of_context_slots();
4399 ++i) {
4400 int context_index =
4401 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
4402 SetProperty(context_ext,
4403 sinfo.context_slot_name(i),
4404 Handle<Object>(function_context->get(context_index)), NONE);
4405 }
4406 // Finally copy any properties from the function context extension. This will
4407 // be variables introduced by eval.
4408 if (function_context->extension() != NULL &&
4409 !function_context->IsGlobalContext()) {
4410 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
4411 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
4412 for (int i = 0; i < keys->length(); i++) {
4413 // Names of variables introduced by eval are strings.
4414 ASSERT(keys->get(i)->IsString());
4415 Handle<String> key(String::cast(keys->get(i)));
4416 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
4417 }
4418 }
4419
4420 // Allocate a new context for the debug evaluation and set the extension
4421 // object build.
4422 Handle<Context> context =
4423 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
4424 context->set_extension(*context_ext);
4425 // Copy any with contexts present and chain them in front of this context.
4426 context = CopyWithContextChain(frame_context, context);
4427
4428 // Wrap the evaluation statement in a new function compiled in the newly
4429 // created context. The function has one parameter which has to be called
4430 // 'arguments'. This it to have access to what would have been 'arguments' in
4431 // the function beeing debugged.
4432 // function(arguments,__source__) {return eval(__source__);}
4433 static const char* source_str =
4434 "function(arguments,__source__){return eval(__source__);}";
4435 static const int source_str_length = strlen(source_str);
4436 Handle<String> function_source =
4437 Factory::NewStringFromAscii(Vector<const char>(source_str,
4438 source_str_length));
4439 Handle<JSFunction> boilerplate =
4440 Compiler::CompileEval(context->IsGlobalContext(), function_source);
4441 if (boilerplate.is_null()) return Failure::Exception();
4442 Handle<JSFunction> compiled_function =
4443 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4444
4445 // Invoke the result of the compilation to get the evaluation function.
4446 bool has_pending_exception;
4447 Handle<Object> receiver(frame->receiver());
4448 Handle<Object> evaluation_function =
4449 Execution::Call(compiled_function, receiver, 0, NULL,
4450 &has_pending_exception);
4451
4452 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
4453 function_context);
4454
4455 // Invoke the evaluation function and return the result.
4456 const int argc = 2;
4457 Object** argv[argc] = { arguments.location(),
4458 Handle<Object>::cast(source).location() };
4459 Handle<Object> result =
4460 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
4461 argc, argv, &has_pending_exception);
4462 return *result;
4463}
4464
4465
4466static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
4467 HandleScope scope;
4468
4469 // Check the execution state and decode arguments frame and source to be
4470 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004471 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 Object* check_result = Runtime_CheckExecutionState(args);
4473 if (check_result->IsFailure()) return check_result;
4474 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004475 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
4476
4477 // Handle the processing of break.
4478 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479
4480 // Enter the top context from before the debugger was invoked.
4481 SaveContext save;
4482 SaveContext* top = &save;
4483 while (top != NULL && *top->context() == *Debug::debug_context()) {
4484 top = top->prev();
4485 }
4486 if (top != NULL) {
4487 Top::set_context(*top->context());
4488 Top::set_security_context(*top->security_context());
4489 }
4490
4491 // Get the global context now set to the top context from before the
4492 // debugger was invoked.
4493 Handle<Context> context = Top::global_context();
4494
4495 // Compile the source to be evaluated.
4496 Handle<JSFunction> boilerplate(Compiler::CompileEval(true, source));
4497 if (boilerplate.is_null()) return Failure::Exception();
4498 Handle<JSFunction> compiled_function =
4499 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
4500 context));
4501
4502 // Invoke the result of the compilation to get the evaluation function.
4503 bool has_pending_exception;
4504 Handle<Object> receiver = Top::global();
4505 Handle<Object> result =
4506 Execution::Call(compiled_function, receiver, 0, NULL,
4507 &has_pending_exception);
4508 return *result;
4509}
4510
4511
4512// Helper function used by Runtime_DebugGetLoadedScripts below.
4513static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
4514 NoHandleAllocation ha;
4515 AssertNoAllocation no_alloc;
4516
4517 // Get hold of the current empty script.
4518 Context* context = Top::context()->global_context();
4519 Script* empty = context->empty_script();
4520
4521 // Scan heap for Script objects.
4522 int count = 0;
4523 HeapIterator iterator;
4524 while (iterator.has_next()) {
4525 HeapObject* obj = iterator.next();
4526 ASSERT(obj != NULL);
4527 if (obj->IsScript() && obj != empty) {
4528 if (instances != NULL && count < instances_size) {
4529 instances->set(count, obj);
4530 }
4531 count++;
4532 }
4533 }
4534
4535 return count;
4536}
4537
4538
4539static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
4540 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004541 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542
4543 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
4544 // rid of all the cached script wrappes and the second gets rid of the
4545 // scripts which is no longer referenced.
4546 Heap::CollectGarbage(0, OLD_SPACE);
4547 Heap::CollectGarbage(0, OLD_SPACE);
4548
4549 // Get the number of scripts.
4550 int count;
4551 count = DebugGetLoadedScripts(NULL, 0);
4552
4553 // Allocate an array to hold the result.
4554 Handle<FixedArray> instances = Factory::NewFixedArray(count);
4555
4556 // Fill the script objects.
4557 count = DebugGetLoadedScripts(*instances, count);
4558
4559 // Convert the script objects to proper JS objects.
4560 for (int i = 0; i < count; i++) {
4561 Handle<Script> script(Script::cast(instances->get(i)));
4562 instances->set(i, *GetScriptWrapper(script));
4563 }
4564
4565 // Return result as a JS array.
4566 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
4567 Handle<JSArray>::cast(result)->SetContent(*instances);
4568 return *result;
4569}
4570
4571
4572// Helper function used by Runtime_DebugReferencedBy below.
4573static int DebugReferencedBy(JSObject* target,
4574 Object* instance_filter, int max_references,
4575 FixedArray* instances, int instances_size,
4576 JSFunction* context_extension_function,
4577 JSFunction* arguments_function) {
4578 NoHandleAllocation ha;
4579 AssertNoAllocation no_alloc;
4580
4581 // Iterate the heap.
4582 int count = 0;
4583 JSObject* last = NULL;
4584 HeapIterator iterator;
4585 while (iterator.has_next() &&
4586 (max_references == 0 || count < max_references)) {
4587 // Only look at all JSObjects.
4588 HeapObject* heap_obj = iterator.next();
4589 if (heap_obj->IsJSObject()) {
4590 // Skip context extension objects and argument arrays as these are
4591 // checked in the context of functions using them.
4592 JSObject* obj = JSObject::cast(heap_obj);
4593 if (obj->map()->constructor() == context_extension_function ||
4594 obj->map()->constructor() == arguments_function) {
4595 continue;
4596 }
4597
4598 // Check if the JS object has a reference to the object looked for.
4599 if (obj->ReferencesObject(target)) {
4600 // Check instance filter if supplied. This is normally used to avoid
4601 // references from mirror objects (see Runtime_IsInPrototypeChain).
4602 if (!instance_filter->IsUndefined()) {
4603 Object* V = obj;
4604 while (true) {
4605 Object* prototype = V->GetPrototype();
4606 if (prototype->IsNull()) {
4607 break;
4608 }
4609 if (instance_filter == prototype) {
4610 obj = NULL; // Don't add this object.
4611 break;
4612 }
4613 V = prototype;
4614 }
4615 }
4616
4617 if (obj != NULL) {
4618 // Valid reference found add to instance array if supplied an update
4619 // count.
4620 if (instances != NULL && count < instances_size) {
4621 instances->set(count, obj);
4622 }
4623 last = obj;
4624 count++;
4625 }
4626 }
4627 }
4628 }
4629
4630 // Check for circular reference only. This can happen when the object is only
4631 // referenced from mirrors and has a circular reference in which case the
4632 // object is not really alive and would have been garbage collected if not
4633 // referenced from the mirror.
4634 if (count == 1 && last == target) {
4635 count = 0;
4636 }
4637
4638 // Return the number of referencing objects found.
4639 return count;
4640}
4641
4642
4643// Scan the heap for objects with direct references to an object
4644// args[0]: the object to find references to
4645// args[1]: constructor function for instances to exclude (Mirror)
4646// args[2]: the the maximum number of objects to return
4647static Object* Runtime_DebugReferencedBy(Arguments args) {
4648 ASSERT(args.length() == 3);
4649
4650 // First perform a full GC in order to avoid references from dead objects.
4651 Heap::CollectGarbage(0, OLD_SPACE);
4652
4653 // Check parameters.
4654 CONVERT_CHECKED(JSObject, target, args[0]);
4655 Object* instance_filter = args[1];
4656 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
4657 instance_filter->IsJSObject());
4658 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
4659 RUNTIME_ASSERT(max_references >= 0);
4660
4661 // Get the constructor function for context extension and arguments array.
4662 JSFunction* context_extension_function =
4663 Top::context()->global_context()->context_extension_function();
4664 JSObject* arguments_boilerplate =
4665 Top::context()->global_context()->arguments_boilerplate();
4666 JSFunction* arguments_function =
4667 JSFunction::cast(arguments_boilerplate->map()->constructor());
4668
4669 // Get the number of referencing objects.
4670 int count;
4671 count = DebugReferencedBy(target, instance_filter, max_references,
4672 NULL, 0,
4673 context_extension_function, arguments_function);
4674
4675 // Allocate an array to hold the result.
4676 Object* object = Heap::AllocateFixedArray(count);
4677 if (object->IsFailure()) return object;
4678 FixedArray* instances = FixedArray::cast(object);
4679
4680 // Fill the referencing objects.
4681 count = DebugReferencedBy(target, instance_filter, max_references,
4682 instances, count,
4683 context_extension_function, arguments_function);
4684
4685 // Return result as JS array.
4686 Object* result =
4687 Heap::AllocateJSObject(
4688 Top::context()->global_context()->array_function());
4689 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
4690 return result;
4691}
4692
4693
4694// Helper function used by Runtime_DebugConstructedBy below.
4695static int DebugConstructedBy(JSFunction* constructor, int max_references,
4696 FixedArray* instances, int instances_size) {
4697 AssertNoAllocation no_alloc;
4698
4699 // Iterate the heap.
4700 int count = 0;
4701 HeapIterator iterator;
4702 while (iterator.has_next() &&
4703 (max_references == 0 || count < max_references)) {
4704 // Only look at all JSObjects.
4705 HeapObject* heap_obj = iterator.next();
4706 if (heap_obj->IsJSObject()) {
4707 JSObject* obj = JSObject::cast(heap_obj);
4708 if (obj->map()->constructor() == constructor) {
4709 // Valid reference found add to instance array if supplied an update
4710 // count.
4711 if (instances != NULL && count < instances_size) {
4712 instances->set(count, obj);
4713 }
4714 count++;
4715 }
4716 }
4717 }
4718
4719 // Return the number of referencing objects found.
4720 return count;
4721}
4722
4723
4724// Scan the heap for objects constructed by a specific function.
4725// args[0]: the constructor to find instances of
4726// args[1]: the the maximum number of objects to return
4727static Object* Runtime_DebugConstructedBy(Arguments args) {
4728 ASSERT(args.length() == 2);
4729
4730 // First perform a full GC in order to avoid dead objects.
4731 Heap::CollectGarbage(0, OLD_SPACE);
4732
4733 // Check parameters.
4734 CONVERT_CHECKED(JSFunction, constructor, args[0]);
4735 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
4736 RUNTIME_ASSERT(max_references >= 0);
4737
4738 // Get the number of referencing objects.
4739 int count;
4740 count = DebugConstructedBy(constructor, max_references, NULL, 0);
4741
4742 // Allocate an array to hold the result.
4743 Object* object = Heap::AllocateFixedArray(count);
4744 if (object->IsFailure()) return object;
4745 FixedArray* instances = FixedArray::cast(object);
4746
4747 // Fill the referencing objects.
4748 count = DebugConstructedBy(constructor, max_references, instances, count);
4749
4750 // Return result as JS array.
4751 Object* result =
4752 Heap::AllocateJSObject(
4753 Top::context()->global_context()->array_function());
4754 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
4755 return result;
4756}
4757
4758
4759static Object* Runtime_GetPrototype(Arguments args) {
4760 ASSERT(args.length() == 1);
4761
4762 CONVERT_CHECKED(JSObject, obj, args[0]);
4763
4764 return obj->GetPrototype();
4765}
4766
4767
4768static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004769 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 CPU::DebugBreak();
4771 return Heap::undefined_value();
4772}
4773
4774
4775// Finds the script object from the script data. NOTE: This operation uses
4776// heap traversal to find the function generated for the source position
4777// for the requested break point. For lazily compiled functions several heap
4778// traversals might be required rendering this operation as a rather slow
4779// operation. However for setting break points which is normally done through
4780// some kind of user interaction the performance is not crucial.
4781static Handle<Object> Runtime_GetScriptFromScriptName(
4782 Handle<String> script_name) {
4783 // Scan the heap for Script objects to find the script with the requested
4784 // script data.
4785 Handle<Script> script;
4786 HeapIterator iterator;
4787 while (script.is_null() && iterator.has_next()) {
4788 HeapObject* obj = iterator.next();
4789 // If a script is found check if it has the script data requested.
4790 if (obj->IsScript()) {
4791 if (Script::cast(obj)->name()->IsString()) {
4792 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
4793 script = Handle<Script>(Script::cast(obj));
4794 }
4795 }
4796 }
4797 }
4798
4799 // If no script with the requested script data is found return undefined.
4800 if (script.is_null()) return Factory::undefined_value();
4801
4802 // Return the script found.
4803 return GetScriptWrapper(script);
4804}
4805
4806
4807// Get the script object from script data. NOTE: Regarding performance
4808// see the NOTE for GetScriptFromScriptData.
4809// args[0]: script data for the script to find the source for
4810static Object* Runtime_GetScript(Arguments args) {
4811 HandleScope scope;
4812
4813 ASSERT(args.length() == 1);
4814
4815 CONVERT_CHECKED(String, script_name, args[0]);
4816
4817 // Find the requested script.
4818 Handle<Object> result =
4819 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
4820 return *result;
4821}
4822
4823
4824static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
4825#ifdef DEBUG
4826 HandleScope scope;
4827 ASSERT(args.length() == 1);
4828 // Get the function and make sure it is compiled.
4829 CONVERT_ARG_CHECKED(JSFunction, func, 0);
4830 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
4831 return Failure::Exception();
4832 }
4833 func->code()->PrintLn();
4834#endif // DEBUG
4835 return Heap::undefined_value();
4836}
4837
4838
4839static Object* Runtime_Abort(Arguments args) {
4840 ASSERT(args.length() == 2);
4841 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
4842 Smi::cast(args[1])->value());
4843 Top::PrintStack();
4844 OS::Abort();
4845 UNREACHABLE();
4846 return NULL;
4847}
4848
4849
kasper.lund44510672008-07-25 07:37:58 +00004850#ifdef DEBUG
4851// ListNatives is ONLY used by the fuzz-natives.js in debug mode
4852// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004853static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004854 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004855 HandleScope scope;
4856 Handle<JSArray> result = Factory::NewJSArray(0);
4857 int index = 0;
4858#define ADD_ENTRY(Name, argc) \
4859 { \
4860 HandleScope inner; \
4861 Handle<String> name = \
4862 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
4863 Handle<JSArray> pair = Factory::NewJSArray(0); \
4864 SetElement(pair, 0, name); \
4865 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
4866 SetElement(result, index++, pair); \
4867 }
4868 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
4869#undef ADD_ENTRY
4870 return *result;
4871}
kasper.lund44510672008-07-25 07:37:58 +00004872#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873
4874
4875static Object* Runtime_IS_VAR(Arguments args) {
4876 UNREACHABLE(); // implemented as macro in the parser
4877 return NULL;
4878}
4879
4880
4881// ----------------------------------------------------------------------------
4882// Implementation of Runtime
4883
4884#define F(name, nargs) \
4885 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
4886 static_cast<int>(Runtime::k##name) },
4887
4888static Runtime::Function Runtime_functions[] = {
4889 RUNTIME_FUNCTION_LIST(F)
4890 { NULL, NULL, NULL, 0, -1 }
4891};
4892
4893#undef F
4894
4895
4896Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
4897 ASSERT(0 <= fid && fid < kNofFunctions);
4898 return &Runtime_functions[fid];
4899}
4900
4901
4902Runtime::Function* Runtime::FunctionForName(const char* name) {
4903 for (Function* f = Runtime_functions; f->name != NULL; f++) {
4904 if (strcmp(f->name, name) == 0) {
4905 return f;
4906 }
4907 }
4908 return NULL;
4909}
4910
4911
4912void Runtime::PerformGC(Object* result) {
4913 Failure* failure = Failure::cast(result);
4914 // Try to do a garbage collection; ignore it if it fails. The C
4915 // entry stub will throw an out-of-memory exception in that case.
4916 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
4917}
4918
4919
4920} } // namespace v8::internal