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