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