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