blob: 8e329b0287ac6015e846a1cb53e239e70767339b [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"
ager@chromium.org7c537e22008-10-16 08:43:32 +000045#include "smart-pointer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47namespace v8 { namespace internal {
48
49
50#define RUNTIME_ASSERT(value) do { \
51 if (!(value)) return IllegalOperation(); \
52} while (false)
53
54// Cast the given object to a value of the specified type and store
55// it in a variable with the given name. If the object is not of the
56// expected type call IllegalOperation and return.
57#define CONVERT_CHECKED(Type, name, obj) \
58 RUNTIME_ASSERT(obj->Is##Type()); \
59 Type* name = Type::cast(obj);
60
61#define CONVERT_ARG_CHECKED(Type, name, index) \
62 RUNTIME_ASSERT(args[index]->Is##Type()); \
63 Handle<Type> name = args.at<Type>(index);
64
kasper.lundbd3ec4e2008-07-09 11:06:54 +000065// Cast the given object to a boolean and store it in a variable with
66// the given name. If the object is not a boolean call IllegalOperation
67// and return.
68#define CONVERT_BOOLEAN_CHECKED(name, obj) \
69 RUNTIME_ASSERT(obj->IsBoolean()); \
70 bool name = (obj)->IsTrue();
71
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072// Cast the given object to a double and store it in a variable with
73// the given name. If the object is not a number (as opposed to
74// the number not-a-number) call IllegalOperation and return.
75#define CONVERT_DOUBLE_CHECKED(name, obj) \
76 RUNTIME_ASSERT(obj->IsNumber()); \
77 double name = (obj)->Number();
78
79// Call the specified converter on the object *comand store the result in
80// a variable of the specified type with the given name. If the
81// object is not a Number call IllegalOperation and return.
82#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
83 RUNTIME_ASSERT(obj->IsNumber()); \
84 type name = NumberTo##Type(obj);
85
86// Non-reentrant string buffer for efficient general use in this file.
87static StaticResource<StringInputBuffer> string_input_buffer;
88
89
90static Object* IllegalOperation() {
91 return Top::Throw(Heap::illegal_access_symbol());
92}
93
94
95static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
96 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 return boilerplate->Copy();
98}
99
100
ager@chromium.org236ad962008-09-25 09:45:57 +0000101static Handle<Map> ComputeObjectLiteralMap(
102 Handle<Context> context,
103 Handle<FixedArray> constant_properties,
104 bool &is_result_from_cache) {
105 if (FLAG_canonicalize_object_literal_maps) {
106 // First find prefix of consecutive symbol keys.
107 int number_of_properties = constant_properties->length()/2;
108 int number_of_symbol_keys = 0;
109 while ((number_of_symbol_keys < number_of_properties) &&
110 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
111 number_of_symbol_keys++;
112 }
113 // Based on the number of prefix symbols key we decide whether
114 // to use the map cache in the global context.
115 const int kMaxKeys = 10;
116 if ((number_of_symbol_keys == number_of_properties)
117 && (number_of_symbol_keys < kMaxKeys)) {
118 // Create the fixed array with the key.
119 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
120 for (int i = 0; i < number_of_symbol_keys; i++) {
121 keys->set(i, constant_properties->get(i*2));
122 }
123 is_result_from_cache = true;
124 return Factory::ObjectLiteralMapFromCache(context, keys);
125 }
126 }
127 is_result_from_cache = false;
128 return Handle<Map>(context->object_function()->initial_map());
129}
130
131
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
133 HandleScope scope;
134 ASSERT(args.length() == 3);
135 // Copy the arguments.
136 Handle<FixedArray> literals = args.at<FixedArray>(0);
137 int literals_index = Smi::cast(args[1])->value();
138 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000139
140 // Get the global context from the literals array. This is the
141 // context in which the function was created and we use the object
142 // function from this context to create the object literal. We do
143 // not use the object function from the current global context
144 // because this might be the object function from another context
145 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000146 Handle<Context> context =
147 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
148
149 bool is_result_from_cache;
150 Handle<Map> map = ComputeObjectLiteralMap(context,
151 constant_properties,
152 is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153
ager@chromium.org236ad962008-09-25 09:45:57 +0000154 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 { // Add the constant propeties to the boilerplate.
156 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000157 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
158 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 for (int index = 0; index < length; index +=2) {
160 Handle<Object> key(constant_properties->get(index+0));
161 Handle<Object> value(constant_properties->get(index+1));
162 uint32_t element_index = 0;
163 if (key->IsSymbol()) {
164 // If key is a symbol it is not an array element.
165 Handle<String> name(String::cast(*key));
166 ASSERT(!name->AsArrayIndex(&element_index));
167 SetProperty(boilerplate, name, value, NONE);
168 } else if (Array::IndexFromObject(*key, &element_index)) {
169 // Array index (uint32).
170 SetElement(boilerplate, element_index, value);
171 } else {
172 // Non-uint32 number.
173 ASSERT(key->IsNumber());
174 double num = key->Number();
175 char arr[100];
176 Vector<char> buffer(arr, ARRAY_SIZE(arr));
177 const char* str = DoubleToCString(num, buffer);
178 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
179 SetProperty(boilerplate, name, value, NONE);
180 }
181 }
182 }
183
184 // Update the functions literal and return the boilerplate.
185 literals->set(literals_index, *boilerplate);
186
187 return *boilerplate;
188}
189
190
191static Object* Runtime_CreateArrayLiteral(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192 // Takes a FixedArray of elements containing the literal elements of
193 // the array literal and produces JSArray with those elements.
194 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000195 // which contains the context from which to get the Array function
196 // to use for creating the array literal.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000197 ASSERT(args.length() == 2);
198 CONVERT_CHECKED(FixedArray, elements, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000199 CONVERT_CHECKED(FixedArray, literals, args[1]);
ager@chromium.org236ad962008-09-25 09:45:57 +0000200 JSFunction* constructor =
201 JSFunction::GlobalContextFromLiterals(literals)->array_function();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000202 // Create the JSArray.
203 Object* object = Heap::AllocateJSObject(constructor);
204 if (object->IsFailure()) return object;
205
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206 // Copy the elements.
207 Object* content = elements->Copy();
208 if (content->IsFailure()) return content;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209
210 // Set the elements.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000211 JSArray::cast(object)->SetContent(FixedArray::cast(content));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 return object;
213}
214
215
216static Object* Runtime_ClassOf(Arguments args) {
217 NoHandleAllocation ha;
218 ASSERT(args.length() == 1);
219 Object* obj = args[0];
220 if (!obj->IsJSObject()) return Heap::null_value();
221 return JSObject::cast(obj)->class_name();
222}
223
ager@chromium.org7c537e22008-10-16 08:43:32 +0000224inline static Object* IsSpecificClassOf(Arguments args, String* name) {
225 NoHandleAllocation ha;
226 ASSERT(args.length() == 1);
227 Object* obj = args[0];
228 if (obj->IsJSObject() && (JSObject::cast(obj)->class_name() == name)) {
229 return Heap::true_value();
230 }
231 return Heap::false_value();
232}
233
234static Object* Runtime_IsStringClass(Arguments args) {
235 return IsSpecificClassOf(args, Heap::String_symbol());
236}
237
238
239static Object* Runtime_IsDateClass(Arguments args) {
240 return IsSpecificClassOf(args, Heap::Date_symbol());
241}
242
243
244static Object* Runtime_IsArrayClass(Arguments args) {
245 return IsSpecificClassOf(args, Heap::Array_symbol());
246}
247
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248
249static Object* Runtime_IsInPrototypeChain(Arguments args) {
250 NoHandleAllocation ha;
251 ASSERT(args.length() == 2);
252 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
253 Object* O = args[0];
254 Object* V = args[1];
255 while (true) {
256 Object* prototype = V->GetPrototype();
257 if (prototype->IsNull()) return Heap::false_value();
258 if (O == prototype) return Heap::true_value();
259 V = prototype;
260 }
261}
262
263
264static Object* Runtime_IsConstructCall(Arguments args) {
265 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000266 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267 JavaScriptFrameIterator it;
268 return Heap::ToBoolean(it.frame()->IsConstructor());
269}
270
271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272static Object* Runtime_RegExpCompile(Arguments args) {
273 HandleScope scope; // create a new handle scope
274 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
276 Handle<JSRegExp> re(raw_re);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 CONVERT_CHECKED(String, raw_pattern, args[1]);
278 Handle<String> pattern(raw_pattern);
279 CONVERT_CHECKED(String, raw_flags, args[2]);
280 Handle<String> flags(raw_flags);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000281 return *RegExpImpl::Compile(re, pattern, flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282}
283
284
285static Object* Runtime_CreateApiFunction(Arguments args) {
286 HandleScope scope;
287 ASSERT(args.length() == 1);
288 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
289 Handle<FunctionTemplateInfo> data(raw_data);
290 return *Factory::CreateApiFunction(data);
291}
292
293
294static Object* Runtime_IsTemplate(Arguments args) {
295 ASSERT(args.length() == 1);
296 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000297 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298 return Heap::ToBoolean(result);
299}
300
301
302static Object* Runtime_GetTemplateField(Arguments args) {
303 ASSERT(args.length() == 2);
304 CONVERT_CHECKED(HeapObject, templ, args[0]);
305 RUNTIME_ASSERT(templ->IsStruct());
306 CONVERT_CHECKED(Smi, field, args[1]);
307 return HeapObject::GetHeapObjectField(templ, field->value());
308}
309
310
311static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
312 HandleScope scope;
313 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
314 Handle<Object> args[2] = { type_handle, name };
315 Handle<Object> error =
316 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
317 return Top::Throw(*error);
318}
319
320
321static Object* Runtime_DeclareGlobals(Arguments args) {
322 HandleScope scope;
323 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
324
325 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
326 Handle<Context> context = args.at<Context>(1);
327 bool is_eval = Smi::cast(args[2])->value() == 1;
328
329 // Compute the property attributes. According to ECMA-262, section
330 // 13, page 71, the property must be read-only and
331 // non-deletable. However, neither SpiderMonkey nor KJS creates the
332 // property as read-only, so we don't either.
333 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
334
335 // Only optimize the object if we intend to add more than 5 properties.
336 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
337
338 // Traverse the name/value pairs and set the properties.
339 int length = pairs->length();
340 for (int i = 0; i < length; i += 2) {
341 HandleScope scope;
342 Handle<String> name(String::cast(pairs->get(i)));
343 Handle<Object> value(pairs->get(i + 1));
344
345 // We have to declare a global const property. To capture we only
346 // assign to it when evaluating the assignment for "const x =
347 // <expr>" the initial value is the hole.
348 bool is_const_property = value->IsTheHole();
349
350 if (value->IsUndefined() || is_const_property) {
351 // Lookup the property in the global object, and don't set the
352 // value of the variable if the property is already there.
353 LookupResult lookup;
354 global->Lookup(*name, &lookup);
355 if (lookup.IsProperty()) {
356 // Determine if the property is local by comparing the holder
357 // against the global object. The information will be used to
358 // avoid throwing re-declaration errors when declaring
359 // variables or constants that exist in the prototype chain.
360 bool is_local = (*global == lookup.holder());
361 // Get the property attributes and determine if the property is
362 // read-only.
363 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
364 bool is_read_only = (attributes & READ_ONLY) != 0;
365 if (lookup.type() == INTERCEPTOR) {
366 // If the interceptor says the property is there, we
367 // just return undefined without overwriting the property.
368 // Otherwise, we continue to setting the property.
369 if (attributes != ABSENT) {
370 // Check if the existing property conflicts with regards to const.
371 if (is_local && (is_read_only || is_const_property)) {
372 const char* type = (is_read_only) ? "const" : "var";
373 return ThrowRedeclarationError(type, name);
374 };
375 // The property already exists without conflicting: Go to
376 // the next declaration.
377 continue;
378 }
379 // Fall-through and introduce the absent property by using
380 // SetProperty.
381 } else {
382 if (is_local && (is_read_only || is_const_property)) {
383 const char* type = (is_read_only) ? "const" : "var";
384 return ThrowRedeclarationError(type, name);
385 }
386 // The property already exists without conflicting: Go to
387 // the next declaration.
388 continue;
389 }
390 }
391 } else {
392 // Copy the function and update its context. Use it as value.
393 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
394 Handle<JSFunction> function =
395 Factory::NewFunctionFromBoilerplate(boilerplate, context);
396 value = function;
397 }
398
399 LookupResult lookup;
400 global->LocalLookup(*name, &lookup);
401
402 PropertyAttributes attributes = is_const_property
403 ? static_cast<PropertyAttributes>(base | READ_ONLY)
404 : base;
405
406 if (lookup.IsProperty()) {
407 // There's a local property that we need to overwrite because
408 // we're either declaring a function or there's an interceptor
409 // that claims the property is absent.
410
411 // Check for conflicting re-declarations. We cannot have
412 // conflicting types in case of intercepted properties because
413 // they are absent.
414 if (lookup.type() != INTERCEPTOR &&
415 (lookup.IsReadOnly() || is_const_property)) {
416 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
417 return ThrowRedeclarationError(type, name);
418 }
419 SetProperty(global, name, value, attributes);
420 } else {
421 // If a property with this name does not already exist on the
422 // global object add the property locally. We take special
423 // precautions to always add it as a local property even in case
424 // of callbacks in the prototype chain (this rules out using
425 // SetProperty). Also, we must use the handle-based version to
426 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000427 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 }
429 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000430
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 return Heap::undefined_value();
432}
433
434
435static Object* Runtime_DeclareContextSlot(Arguments args) {
436 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000437 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438
ager@chromium.org7c537e22008-10-16 08:43:32 +0000439 CONVERT_ARG_CHECKED(Context, context, 0);
440 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000442 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000443 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000444 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445
446 // Declarations are always done in the function context.
447 context = Handle<Context>(context->fcontext());
448
449 int index;
450 PropertyAttributes attributes;
451 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
452 Handle<Object> context_obj =
453 context->Lookup(name, flags, &index, &attributes);
454
455 if (attributes != ABSENT) {
456 // The name was declared before; check for conflicting
457 // re-declarations: This is similar to the code in parser.cc in
458 // the AstBuildingParser::Declare function.
459 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
460 // Functions are not read-only.
461 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
462 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
463 return ThrowRedeclarationError(type, name);
464 }
465
466 // Initialize it if necessary.
467 if (*initial_value != NULL) {
468 if (index >= 0) {
469 // The variable or constant context slot should always be in
470 // the function context; not in any outer context nor in the
471 // arguments object.
472 ASSERT(context_obj.is_identical_to(context));
473 if (((attributes & READ_ONLY) == 0) ||
474 context->get(index)->IsTheHole()) {
475 context->set(index, *initial_value);
476 }
477 } else {
478 // Slow case: The property is not in the FixedArray part of the context.
479 Handle<JSObject> context_ext = Handle<JSObject>::cast(context_obj);
480 SetProperty(context_ext, name, initial_value, mode);
481 }
482 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000483
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000485 // The property is not in the function context. It needs to be
486 // "declared" in the function context's extension context, or in the
487 // global context.
488 Handle<JSObject> context_ext;
489 if (context->extension() != NULL) {
490 // The function context's extension context exists - use it.
491 context_ext = Handle<JSObject>(context->extension());
492 } else {
493 // The function context's extension context does not exists - allocate
494 // it.
495 context_ext = Factory::NewJSObject(Top::context_extension_function());
496 // And store it in the extension slot.
497 context->set_extension(*context_ext);
498 }
499 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500
ager@chromium.org7c537e22008-10-16 08:43:32 +0000501 // Declare the property by setting it to the initial value if provided,
502 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
503 // constant declarations).
504 ASSERT(!context_ext->HasLocalProperty(*name));
505 Handle<Object> value(Heap::undefined_value());
506 if (*initial_value != NULL) value = initial_value;
507 SetProperty(context_ext, name, value, mode);
508 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
509 }
510
511 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512}
513
514
515static Object* Runtime_InitializeVarGlobal(Arguments args) {
516 NoHandleAllocation nha;
517
518 // Determine if we need to assign to the variable if it already
519 // exists (based on the number of arguments).
520 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
521 bool assign = args.length() == 2;
522
523 CONVERT_ARG_CHECKED(String, name, 0);
524 GlobalObject* global = Top::context()->global();
525
526 // According to ECMA-262, section 12.2, page 62, the property must
527 // not be deletable.
528 PropertyAttributes attributes = DONT_DELETE;
529
530 // Lookup the property locally in the global object. If it isn't
531 // there, we add the property and take special precautions to always
532 // add it as a local property even in case of callbacks in the
533 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000534 // We have IgnoreAttributesAndSetLocalProperty for this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535 LookupResult lookup;
536 global->LocalLookup(*name, &lookup);
537 if (!lookup.IsProperty()) {
538 Object* value = (assign) ? args[1] : Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000539 return global->IgnoreAttributesAndSetLocalProperty(*name,
540 value,
541 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 }
543
544 // Determine if this is a redeclaration of something read-only.
545 if (lookup.IsReadOnly()) {
546 return ThrowRedeclarationError("const", name);
547 }
548
549 // Determine if this is a redeclaration of an intercepted read-only
550 // property and figure out if the property exists at all.
551 bool found = true;
552 PropertyType type = lookup.type();
553 if (type == INTERCEPTOR) {
554 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
555 if (intercepted == ABSENT) {
556 // The interceptor claims the property isn't there. We need to
557 // make sure to introduce it.
558 found = false;
559 } else if ((intercepted & READ_ONLY) != 0) {
560 // The property is present, but read-only. Since we're trying to
561 // overwrite it with a variable declaration we must throw a
562 // re-declaration error.
563 return ThrowRedeclarationError("const", name);
564 }
565 // Restore global object from context (in case of GC).
566 global = Top::context()->global();
567 }
568
569 if (found && !assign) {
570 // The global property is there and we're not assigning any value
571 // to it. Just return.
572 return Heap::undefined_value();
573 }
574
575 // Assign the value (or undefined) to the property.
576 Object* value = (assign) ? args[1] : Heap::undefined_value();
577 return global->SetProperty(&lookup, *name, value, attributes);
578}
579
580
581static Object* Runtime_InitializeConstGlobal(Arguments args) {
582 // All constants are declared with an initial value. The name
583 // of the constant is the first argument and the initial value
584 // is the second.
585 RUNTIME_ASSERT(args.length() == 2);
586 CONVERT_ARG_CHECKED(String, name, 0);
587 Handle<Object> value = args.at<Object>(1);
588
589 // Get the current global object from top.
590 GlobalObject* global = Top::context()->global();
591
592 // According to ECMA-262, section 12.2, page 62, the property must
593 // not be deletable. Since it's a const, it must be READ_ONLY too.
594 PropertyAttributes attributes =
595 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
596
597 // Lookup the property locally in the global object. If it isn't
598 // there, we add the property and take special precautions to always
599 // add it as a local property even in case of callbacks in the
600 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000601 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602 LookupResult lookup;
603 global->LocalLookup(*name, &lookup);
604 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000605 return global->IgnoreAttributesAndSetLocalProperty(*name,
606 *value,
607 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608 }
609
610 // Determine if this is a redeclaration of something not
611 // read-only. In case the result is hidden behind an interceptor we
612 // need to ask it for the property attributes.
613 if (!lookup.IsReadOnly()) {
614 if (lookup.type() != INTERCEPTOR) {
615 return ThrowRedeclarationError("var", name);
616 }
617
618 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
619
620 // Throw re-declaration error if the intercepted property is present
621 // but not read-only.
622 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
623 return ThrowRedeclarationError("var", name);
624 }
625
626 // Restore global object from context (in case of GC) and continue
627 // with setting the value because the property is either absent or
628 // read-only. We also have to do redo the lookup.
629 global = Top::context()->global();
630
631 // BUG 1213579: Handle the case where we have to set a read-only
632 // property through an interceptor and only do it if it's
633 // uninitialized, e.g. the hole. Nirk...
634 global->SetProperty(*name, *value, attributes);
635 return *value;
636 }
637
638 // Set the value, but only we're assigning the initial value to a
639 // constant. For now, we determine this by checking if the
640 // current value is the hole.
641 PropertyType type = lookup.type();
642 if (type == FIELD) {
643 FixedArray* properties = global->properties();
644 int index = lookup.GetFieldIndex();
645 if (properties->get(index)->IsTheHole()) {
646 properties->set(index, *value);
647 }
648 } else if (type == NORMAL) {
649 Dictionary* dictionary = global->property_dictionary();
650 int entry = lookup.GetDictionaryEntry();
651 if (dictionary->ValueAt(entry)->IsTheHole()) {
652 dictionary->ValueAtPut(entry, *value);
653 }
654 } else {
655 // Ignore re-initialization of constants that have already been
656 // assigned a function value.
657 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
658 }
659
660 // Use the set value as the result of the operation.
661 return *value;
662}
663
664
665static Object* Runtime_InitializeConstContextSlot(Arguments args) {
666 HandleScope scope;
667 ASSERT(args.length() == 3);
668
669 Handle<Object> value(args[0]);
670 ASSERT(!value->IsTheHole());
671 CONVERT_ARG_CHECKED(Context, context, 1);
672 Handle<String> name(String::cast(args[2]));
673
674 // Initializations are always done in the function context.
675 context = Handle<Context>(context->fcontext());
676
677 int index;
678 PropertyAttributes attributes;
679 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
680 Handle<Object> context_obj =
681 context->Lookup(name, flags, &index, &attributes);
682
683 // The property should always be present. It is always declared
684 // before being initialized through DeclareContextSlot.
685 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
686
687 // If the slot is in the context, we set it but only if it hasn't
688 // been set before.
689 if (index >= 0) {
690 // The constant context slot should always be in the function
691 // context; not in any outer context nor in the arguments object.
692 ASSERT(context_obj.is_identical_to(context));
693 if (context->get(index)->IsTheHole()) {
694 context->set(index, *value);
695 }
696 return *value;
697 }
698
699 // Otherwise, the slot must be in a JS object extension.
700 Handle<JSObject> context_ext(JSObject::cast(*context_obj));
701
702 // We must initialize the value only if it wasn't initialized
703 // before, e.g. for const declarations in a loop. The property has
704 // the hole value if it wasn't initialized yet. NOTE: We cannot use
705 // GetProperty() to get the current value as it 'unholes' the value.
706 LookupResult lookup;
707 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
708 ASSERT(lookup.IsProperty()); // the property was declared
709 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
710
711 PropertyType type = lookup.type();
712 if (type == FIELD) {
713 FixedArray* properties = context_ext->properties();
714 int index = lookup.GetFieldIndex();
715 if (properties->get(index)->IsTheHole()) {
716 properties->set(index, *value);
717 }
718 } else if (type == NORMAL) {
719 Dictionary* dictionary = context_ext->property_dictionary();
720 int entry = lookup.GetDictionaryEntry();
721 if (dictionary->ValueAt(entry)->IsTheHole()) {
722 dictionary->ValueAtPut(entry, *value);
723 }
724 } else {
725 // We should not reach here. Any real, named property should be
726 // either a field or a dictionary slot.
727 UNREACHABLE();
728 }
729 return *value;
730}
731
732
733static Object* Runtime_RegExpExec(Arguments args) {
734 HandleScope scope;
735 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000736 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
737 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000738 CONVERT_CHECKED(String, raw_subject, args[1]);
739 Handle<String> subject(raw_subject);
740 Handle<Object> index(args[2]);
741 ASSERT(index->IsNumber());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000742 return *RegExpImpl::Exec(regexp, subject, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743}
744
745
746static Object* Runtime_RegExpExecGlobal(Arguments args) {
747 HandleScope scope;
748 ASSERT(args.length() == 2);
ager@chromium.org236ad962008-09-25 09:45:57 +0000749 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
750 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 CONVERT_CHECKED(String, raw_subject, args[1]);
752 Handle<String> subject(raw_subject);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000753 return *RegExpImpl::ExecGlobal(regexp, subject);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754}
755
756
757static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
758 HandleScope scope;
759 ASSERT(args.length() == 4);
760 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
761 int index = Smi::cast(args[1])->value();
762 Handle<String> pattern = args.at<String>(2);
763 Handle<String> flags = args.at<String>(3);
764
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000765 // Get the RegExp function from the context in the literals array.
766 // This is the RegExp function from the context in which the
767 // function was created. We do not use the RegExp function from the
768 // current global context because this might be the RegExp function
769 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000770 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +0000771 Handle<JSFunction>(
772 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 // Compute the regular expression literal.
774 bool has_pending_exception;
775 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000776 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
777 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778 if (has_pending_exception) {
779 ASSERT(Top::has_pending_exception());
780 return Failure::Exception();
781 }
782 literals->set(index, *regexp);
783 return *regexp;
784}
785
786
787static Object* Runtime_FunctionGetName(Arguments args) {
788 NoHandleAllocation ha;
789 ASSERT(args.length() == 1);
790
791 CONVERT_CHECKED(JSFunction, f, args[0]);
792 return f->shared()->name();
793}
794
795
ager@chromium.org236ad962008-09-25 09:45:57 +0000796static Object* Runtime_FunctionSetName(Arguments args) {
797 NoHandleAllocation ha;
798 ASSERT(args.length() == 2);
799
800 CONVERT_CHECKED(JSFunction, f, args[0]);
801 CONVERT_CHECKED(String, name, args[1]);
802 f->shared()->set_name(name);
803 return Heap::undefined_value();
804}
805
806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807static Object* Runtime_FunctionGetScript(Arguments args) {
808 HandleScope scope;
809 ASSERT(args.length() == 1);
810
811 CONVERT_CHECKED(JSFunction, fun, args[0]);
812 Handle<Object> script = Handle<Object>(fun->shared()->script());
813 if (!script->IsScript()) return Heap::undefined_value();
814
815 return *GetScriptWrapper(Handle<Script>::cast(script));
816}
817
818
819static Object* Runtime_FunctionGetSourceCode(Arguments args) {
820 NoHandleAllocation ha;
821 ASSERT(args.length() == 1);
822
823 CONVERT_CHECKED(JSFunction, f, args[0]);
824 return f->shared()->GetSourceCode();
825}
826
827
828static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
829 NoHandleAllocation ha;
830 ASSERT(args.length() == 1);
831
832 CONVERT_CHECKED(JSFunction, fun, args[0]);
833 int pos = fun->shared()->start_position();
834 return Smi::FromInt(pos);
835}
836
837
838static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
839 NoHandleAllocation ha;
840 ASSERT(args.length() == 2);
841
842 CONVERT_CHECKED(JSFunction, fun, args[0]);
843 CONVERT_CHECKED(String, name, args[1]);
844 fun->SetInstanceClassName(name);
845 return Heap::undefined_value();
846}
847
848
849static Object* Runtime_FunctionSetLength(Arguments args) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 2);
852
853 CONVERT_CHECKED(JSFunction, fun, args[0]);
854 CONVERT_CHECKED(Smi, length, args[1]);
855 fun->shared()->set_length(length->value());
856 return length;
857}
858
859
860static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000861 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862 ASSERT(args.length() == 2);
863
864 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000865 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
866 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867 return args[0]; // return TOS
868}
869
870
871static Object* Runtime_SetCode(Arguments args) {
872 HandleScope scope;
873 ASSERT(args.length() == 2);
874
875 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
876 Handle<JSFunction> target(raw_target);
877 Handle<Object> code = args.at<Object>(1);
878
879 Handle<Context> context(target->context());
880
881 if (!code->IsNull()) {
882 RUNTIME_ASSERT(code->IsJSFunction());
883 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
884 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
885 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
886 return Failure::Exception();
887 }
888 // Set the code, formal parameter count, and the length of the target
889 // function.
890 target->set_code(fun->code());
891 target->shared()->set_length(fun->shared()->length());
892 target->shared()->set_formal_parameter_count(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000893 fun->shared()->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +0000894 // Set the source code of the target function to undefined.
895 // SetCode is only used for built-in constructors like String,
896 // Array, and Object, and some web code
897 // doesn't like seeing source code for constructors.
898 target->shared()->set_script(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 context = Handle<Context>(fun->context());
900
901 // Make sure we get a fresh copy of the literal vector to avoid
902 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000903 int number_of_literals = fun->NumberOfLiterals();
904 Handle<FixedArray> literals =
905 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000907 // Insert the object, regexp and array functions in the literals
908 // array prefix. These are the functions that will be used when
909 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +0000910 literals->set(JSFunction::kLiteralGlobalContextIndex,
911 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000913 target->set_literals(*literals);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 }
915
916 target->set_context(*context);
917 return *target;
918}
919
920
921static Object* CharCodeAt(String* subject, Object* index) {
922 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000923 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924 // Flatten the string. If someone wants to get a char at an index
925 // in a cons string, it is likely that more indices will be
926 // accessed.
927 subject->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000928 if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000929 return Smi::FromInt(subject->Get(i));
930}
931
932
933static Object* Runtime_StringCharCodeAt(Arguments args) {
934 NoHandleAllocation ha;
935 ASSERT(args.length() == 2);
936
937 CONVERT_CHECKED(String, subject, args[0]);
938 Object* index = args[1];
939 return CharCodeAt(subject, index);
940}
941
942
943static Object* Runtime_CharFromCode(Arguments args) {
944 NoHandleAllocation ha;
945 ASSERT(args.length() == 1);
946 uint32_t code;
947 if (Array::IndexFromObject(args[0], &code)) {
948 if (code <= 0xffff) {
949 return Heap::LookupSingleCharacterStringFromCode(code);
950 }
951 }
952 return Heap::empty_string();
953}
954
955
ager@chromium.org7c537e22008-10-16 08:43:32 +0000956// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
957// limit, we can fix the size of tables.
958static const int kBMMaxShift = 0xff;
959static const int kBMAlphabetSize = 0x100; // Reduce alphabet to this size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960
ager@chromium.org7c537e22008-10-16 08:43:32 +0000961// Holds the two buffers used by Boyer-Moore string search's Good Suffix
962// shift. Only allows the last kBMMaxShift characters of the needle
963// to be indexed.
964class BMGoodSuffixBuffers: public AllStatic {
965 public:
966 BMGoodSuffixBuffers() {}
967 inline void init(int needle_length) {
968 ASSERT(needle_length > 1);
969 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
970 int len = needle_length - start;
971 biased_suffixes_ = suffixes_ - start;
972 biased_good_suffix_shift_ = good_suffix_shift_ - start;
973 for (int i = 0; i <= len; i++) {
974 good_suffix_shift_[i] = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000976 }
977 inline int& suffix(int index) {
978 ASSERT(biased_suffixes_ + index >= suffixes_);
979 return biased_suffixes_[index];
980 }
981 inline int& shift(int index) {
982 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
983 return biased_good_suffix_shift_[index];
984 }
985 private:
986 int suffixes_[kBMMaxShift + 1];
987 int good_suffix_shift_[kBMMaxShift + 1];
988 int *biased_suffixes_;
989 int *biased_good_suffix_shift_;
990 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
991};
992
993// buffers reused by BoyerMoore
994static int bad_char_occurence[kBMAlphabetSize];
995static BMGoodSuffixBuffers bmgs_buffers;
996
997// Compute the bad-char table for Boyer-Moore in the static buffer.
998// Return false if the pattern contains non-ASCII characters that cannot be
999// in the searched string.
1000template <typename pchar>
1001static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern,
1002 int start) {
1003 // Run forwards to populate bad_char_table, so that *last* instance
1004 // of character equivalence class is the one registered.
1005 // Notice: Doesn't include the last character.
1006 for (int i = 0; i < kBMAlphabetSize; i++) {
1007 bad_char_occurence[i] = start - 1;
1008 }
1009 for (int i = start; i < pattern.length(); i++) {
1010 bad_char_occurence[pattern[i] % kBMAlphabetSize] = i;
1011 }
1012}
1013
1014template <typename pchar>
1015static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern,
1016 int start,
1017 int len) {
1018 int m = pattern.length();
1019 // Compute Good Suffix tables.
1020 bmgs_buffers.init(m);
1021
1022 bmgs_buffers.shift(m-1) = 1;
1023 bmgs_buffers.suffix(m) = m + 1;
1024 pchar last_char = pattern[m - 1];
1025 int suffix = m + 1;
1026 for (int i = m; i > start;) {
1027 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
1028 if (bmgs_buffers.shift(suffix) == len) {
1029 bmgs_buffers.shift(suffix) = suffix - i;
1030 }
1031 suffix = bmgs_buffers.suffix(suffix);
1032 }
1033 i--;
1034 suffix--;
1035 bmgs_buffers.suffix(i) = suffix;
1036 if (suffix == m) {
1037 // No suffix to extend, so we check against last_char only.
1038 while (i > start && pattern[i - 1] != last_char) {
1039 if (bmgs_buffers.shift(m) == len) {
1040 bmgs_buffers.shift(m) = m - i;
1041 }
1042 i--;
1043 bmgs_buffers.suffix(i) = m;
1044 }
1045 if (i > start) {
1046 i--;
1047 suffix--;
1048 bmgs_buffers.suffix(i) = suffix;
1049 }
1050 }
1051 }
1052 if (suffix < m) {
1053 for (int i = start; i <= m; i++) {
1054 if (bmgs_buffers.shift(i) == len) {
1055 bmgs_buffers.shift(i) = suffix - start;
1056 }
1057 if (i == suffix) {
1058 suffix = bmgs_buffers.suffix(suffix);
1059 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 }
1061 }
1062}
1063
ager@chromium.org7c537e22008-10-16 08:43:32 +00001064// Restricted Boyer-Moore string matching. Restricts tables to a
1065// suffix of long pattern strings and handles only equivalence classes
1066// of the full alphabet. This allows us to ensure that tables take only
1067// a fixed amount of space.
1068template <typename schar, typename pchar>
1069static int BoyerMooreIndexOf(Vector<const schar> subject,
1070 Vector<const pchar> pattern,
1071 int start_index) {
1072 int m = pattern.length();
1073 int n = subject.length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074
ager@chromium.org7c537e22008-10-16 08:43:32 +00001075 // Only preprocess at most kBMMaxShift last characters of pattern.
1076 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
1077 int len = m - start;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078
ager@chromium.org7c537e22008-10-16 08:43:32 +00001079 BoyerMoorePopulateBadCharTable(pattern, start);
1080
1081 int badness = 0; // How bad we are doing without a good-suffix table.
1082 int idx; // No matches found prior to this index.
1083 // Perform search
1084 for (idx = start_index; idx <= n - m;) {
1085 int j = m - 1;
1086 schar c;
1087 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1088 if (j < 0) {
1089 return idx;
1090 } else {
1091 int bc_occ = bad_char_occurence[c % kBMAlphabetSize];
1092 int shift = bc_occ < j ? j - bc_occ : 1;
1093 idx += shift;
1094 // Badness increases by the number of characters we have
1095 // checked, and decreases by the number of characters we
1096 // can skip by shifting. It's a measure of how we are doing
1097 // compared to reading each character exactly once.
1098 badness += (m - j) - shift;
1099 if (badness > m) break;
1100 }
1101 }
1102
1103 // If we are not done, we got here because we should build the Good Suffix
1104 // table and continue searching.
1105 if (idx <= n - m) {
1106 BoyerMoorePopulateGoodSuffixTable(pattern, start, len);
1107 // Continue search from i.
1108 do {
1109 int j = m - 1;
1110 schar c;
1111 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1112 if (j < 0) {
1113 return idx;
1114 } else if (j < start) {
1115 // we have matched more than our tables allow us to be smart about.
1116 idx += 1;
1117 } else {
1118 int gs_shift = bmgs_buffers.shift(j + 1);
1119 int bc_occ = bad_char_occurence[c % kBMAlphabetSize];
1120 int bc_shift = j - bc_occ;
1121 idx += (gs_shift > bc_shift) ? gs_shift : bc_shift;
1122 }
1123 } while (idx <= n - m);
1124 }
1125
1126 return -1;
1127}
1128
1129template <typename schar, typename pchar>
1130static int SingleCharIndexOf(Vector<const schar> string,
1131 pchar pattern_char,
1132 int start_index) {
1133 for (int i = start_index, n = string.length(); i < n; i++) {
1134 if (pattern_char == string[i]) {
1135 return i;
1136 }
1137 }
1138 return -1;
1139}
1140
1141// Trivial string search for shorter strings.
1142// On return, if "complete" is set to true, the return value is the
1143// final result of searching for the patter in the subject.
1144// If "complete" is set to false, the return value is the index where
1145// further checking should start, i.e., it's guaranteed that the pattern
1146// does not occur at a position prior to the returned index.
1147template <typename pchar, typename schar>
1148static int SimpleIndexOf(Vector<const schar> subject,
1149 Vector<const pchar> pattern,
1150 int start_index,
1151 bool &complete) {
1152 int pattern_length = pattern.length();
1153 int subject_length = subject.length();
1154 // Badness is a count of how many extra times the same character
1155 // is checked. We compare it to the index counter, so we start
1156 // it at the start_index, and give it a little discount to avoid
1157 // very early bail-outs.
1158 int badness = start_index - pattern_length;
1159 // We know our pattern is at least 2 characters, we cache the first so
1160 // the common case of the first character not matching is faster.
1161 pchar pattern_first_char = pattern[0];
1162
1163 for (int i = start_index, n = subject_length - pattern_length; i <= n; i++) {
1164 if (subject[i] != pattern_first_char) continue;
1165 int j = 1;
1166 do {
1167 if (pattern[j] != subject[i+j]) {
1168 break;
1169 }
1170 j++;
1171 } while (j < pattern_length);
1172 if (j == pattern_length) {
1173 complete = true;
1174 return i;
1175 }
1176 badness += j;
1177 if (badness > i) { // More than one extra character on average.
1178 complete = false;
1179 return (i + 1); // No matches up to index i+1.
1180 }
1181 }
1182 complete = true;
1183 return -1;
1184}
1185
1186// Dispatch to different algorithms for different length of pattern/subject
1187template <typename schar, typename pchar>
1188static int StringMatchStrategy(Vector<const schar> sub,
1189 Vector<const pchar> pat,
1190 int start_index) {
1191 ASSERT(pat.length() > 1);
1192
1193 // We have an ASCII haystack and a non-ASCII needle. Check if there
1194 // really is a non-ASCII character in the needle and bail out if there
1195 // is.
1196 if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
1197 for (int i = 0; i < pat.length(); i++) {
1198 uc16 c = pat[i];
1199 if (c > String::kMaxAsciiCharCode) {
1200 return -1;
1201 }
1202 }
1203 }
1204 // For small searches, a complex sort is not worth the setup overhead.
1205 bool complete;
1206 int idx = SimpleIndexOf(sub, pat, start_index, complete);
1207 if (complete) return idx;
1208 return BoyerMooreIndexOf(sub, pat, idx);
1209}
1210
1211// Perform string match of pattern on subject, starting at start index.
1212// Caller must ensure that 0 <= start_index <= sub->length(),
1213// and should check that pat->length() + start_index <= sub->length()
1214int Runtime::StringMatch(Handle<String> sub,
1215 Handle<String> pat,
1216 int start_index) {
1217 ASSERT(0 <= start_index);
1218 ASSERT(start_index <= sub->length());
1219
ager@chromium.org236ad962008-09-25 09:45:57 +00001220 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001221 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222
ager@chromium.org7c537e22008-10-16 08:43:32 +00001223 int subject_length = sub->length();
1224 if (start_index + pattern_length > subject_length) return -1;
1225
1226 FlattenString(sub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227 // Searching for one specific character is common. For one
ager@chromium.org7c537e22008-10-16 08:43:32 +00001228 // character patterns linear search is necessary, so any smart
1229 // algorithm is unnecessary overhead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 if (pattern_length == 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001231 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1232 if (sub->is_ascii_representation()) {
1233 return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001235 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 }
1237
ager@chromium.org7c537e22008-10-16 08:43:32 +00001238 FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00001239
ager@chromium.org7c537e22008-10-16 08:43:32 +00001240 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1241 // dispatch on type of strings
1242 if (pat->is_ascii_representation()) {
1243 Vector<const char> pat_vector = pat->ToAsciiVector();
1244 if (sub->is_ascii_representation()) {
1245 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001246 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001247 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001248 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001249 Vector<const uc16> pat_vector = pat->ToUC16Vector();
1250 if (sub->is_ascii_representation()) {
1251 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001253 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001254}
1255
1256
1257static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001258 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001259 ASSERT(args.length() == 3);
1260
ager@chromium.org7c537e22008-10-16 08:43:32 +00001261 CONVERT_ARG_CHECKED(String, sub, 0);
1262 CONVERT_ARG_CHECKED(String, pat, 1);
1263
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001264 Object* index = args[2];
1265 uint32_t start_index;
1266 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1267
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 int position = Runtime::StringMatch(sub, pat, start_index);
1269 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270}
1271
1272
1273static Object* Runtime_StringLastIndexOf(Arguments args) {
1274 NoHandleAllocation ha;
1275 ASSERT(args.length() == 3);
1276
1277 CONVERT_CHECKED(String, sub, args[0]);
1278 CONVERT_CHECKED(String, pat, args[1]);
1279 Object* index = args[2];
1280
1281 sub->TryFlatten();
1282 pat->TryFlatten();
1283
1284 uint32_t start_index;
1285 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1286
1287 uint32_t pattern_length = pat->length();
1288 uint32_t sub_length = sub->length();
1289
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001290 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001292 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293
1294 for (int i = start_index; i >= 0; i--) {
1295 bool found = true;
1296 for (uint32_t j = 0; j < pattern_length; j++) {
1297 if (sub->Get(i + j) != pat->Get(j)) {
1298 found = false;
1299 break;
1300 }
1301 }
1302 if (found) return Smi::FromInt(i);
1303 }
1304
1305 return Smi::FromInt(-1);
1306}
1307
1308
1309static Object* Runtime_StringLocaleCompare(Arguments args) {
1310 NoHandleAllocation ha;
1311 ASSERT(args.length() == 2);
1312
1313 CONVERT_CHECKED(String, str1, args[0]);
1314 CONVERT_CHECKED(String, str2, args[1]);
1315
1316 if (str1 == str2) return Smi::FromInt(0); // Equal.
1317 int str1_length = str1->length();
1318 int str2_length = str2->length();
1319
1320 // Decide trivial cases without flattening.
1321 if (str1_length == 0) {
1322 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1323 return Smi::FromInt(-str2_length);
1324 } else {
1325 if (str2_length == 0) return Smi::FromInt(str1_length);
1326 }
1327
1328 int end = str1_length < str2_length ? str1_length : str2_length;
1329
1330 // No need to flatten if we are going to find the answer on the first
1331 // character. At this point we know there is at least one character
1332 // in each string, due to the trivial case handling above.
1333 int d = str1->Get(0) - str2->Get(0);
1334 if (d != 0) return Smi::FromInt(d);
1335
1336 str1->TryFlatten();
1337 str2->TryFlatten();
1338
1339 static StringInputBuffer buf1;
1340 static StringInputBuffer buf2;
1341
1342 buf1.Reset(str1);
1343 buf2.Reset(str2);
1344
1345 for (int i = 0; i < end; i++) {
1346 uint16_t char1 = buf1.GetNext();
1347 uint16_t char2 = buf2.GetNext();
1348 if (char1 != char2) return Smi::FromInt(char1 - char2);
1349 }
1350
1351 return Smi::FromInt(str1_length - str2_length);
1352}
1353
1354
1355static Object* Runtime_StringSlice(Arguments args) {
1356 NoHandleAllocation ha;
1357 ASSERT(args.length() == 3);
1358
1359 CONVERT_CHECKED(String, value, args[0]);
1360 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1361 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1362
1363 int start = FastD2I(from_number);
1364 int end = FastD2I(to_number);
1365
1366 RUNTIME_ASSERT(end >= start);
1367 RUNTIME_ASSERT(start >= 0);
1368 RUNTIME_ASSERT(end <= value->length());
1369 return value->Slice(start, end);
1370}
1371
1372
1373static Object* Runtime_NumberToRadixString(Arguments args) {
1374 NoHandleAllocation ha;
1375 ASSERT(args.length() == 2);
1376
1377 CONVERT_DOUBLE_CHECKED(value, args[0]);
1378 if (isnan(value)) {
1379 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1380 }
1381 if (isinf(value)) {
1382 if (value < 0) {
1383 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1384 }
1385 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1386 }
1387 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1388 int radix = FastD2I(radix_number);
1389 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1390 char* str = DoubleToRadixCString(value, radix);
1391 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1392 DeleteArray(str);
1393 return result;
1394}
1395
1396
1397static Object* Runtime_NumberToFixed(Arguments args) {
1398 NoHandleAllocation ha;
1399 ASSERT(args.length() == 2);
1400
1401 CONVERT_DOUBLE_CHECKED(value, args[0]);
1402 if (isnan(value)) {
1403 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1404 }
1405 if (isinf(value)) {
1406 if (value < 0) {
1407 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1408 }
1409 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1410 }
1411 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1412 int f = FastD2I(f_number);
1413 RUNTIME_ASSERT(f >= 0);
1414 char* str = DoubleToFixedCString(value, f);
1415 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1416 DeleteArray(str);
1417 return res;
1418}
1419
1420
1421static Object* Runtime_NumberToExponential(Arguments args) {
1422 NoHandleAllocation ha;
1423 ASSERT(args.length() == 2);
1424
1425 CONVERT_DOUBLE_CHECKED(value, args[0]);
1426 if (isnan(value)) {
1427 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1428 }
1429 if (isinf(value)) {
1430 if (value < 0) {
1431 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1432 }
1433 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1434 }
1435 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1436 int f = FastD2I(f_number);
1437 RUNTIME_ASSERT(f >= -1 && f <= 20);
1438 char* str = DoubleToExponentialCString(value, f);
1439 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1440 DeleteArray(str);
1441 return res;
1442}
1443
1444
1445static Object* Runtime_NumberToPrecision(Arguments args) {
1446 NoHandleAllocation ha;
1447 ASSERT(args.length() == 2);
1448
1449 CONVERT_DOUBLE_CHECKED(value, args[0]);
1450 if (isnan(value)) {
1451 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1452 }
1453 if (isinf(value)) {
1454 if (value < 0) {
1455 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1456 }
1457 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1458 }
1459 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1460 int f = FastD2I(f_number);
1461 RUNTIME_ASSERT(f >= 1 && f <= 21);
1462 char* str = DoubleToPrecisionCString(value, f);
1463 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1464 DeleteArray(str);
1465 return res;
1466}
1467
1468
1469// Returns a single character string where first character equals
1470// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001471static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 if (index < static_cast<uint32_t>(string->length())) {
1473 string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001474 return LookupSingleCharacterStringFromCode(string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001476 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477}
1478
1479
1480Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1481 // Handle [] indexing on Strings
1482 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001483 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1484 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 }
1486
1487 // Handle [] indexing on String objects
1488 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001489 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1490 Handle<Object> result =
1491 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1492 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 }
1494
1495 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001496 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 return prototype->GetElement(index);
1498 }
1499
1500 return object->GetElement(index);
1501}
1502
1503
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001504Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1505 HandleScope scope;
1506
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001508 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 Handle<Object> error =
1510 Factory::NewTypeError("non_object_property_load",
1511 HandleVector(args, 2));
1512 return Top::Throw(*error);
1513 }
1514
1515 // Check if the given key is an array index.
1516 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001517 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518 return GetElementOrCharAt(object, index);
1519 }
1520
1521 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001522 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001524 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 bool has_pending_exception = false;
1527 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001528 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001530 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 }
1532
1533 // Check if the name is trivially convertable to an index and get
1534 // the element if so.
1535 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 return GetElementOrCharAt(object, index);
1537 } else {
1538 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001539 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 }
1541}
1542
1543
1544static Object* Runtime_GetProperty(Arguments args) {
1545 NoHandleAllocation ha;
1546 ASSERT(args.length() == 2);
1547
1548 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001549 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550
1551 return Runtime::GetObjectProperty(object, key);
1552}
1553
1554
ager@chromium.org7c537e22008-10-16 08:43:32 +00001555
1556// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric
1557static Object* Runtime_KeyedGetProperty(Arguments args) {
1558 NoHandleAllocation ha;
1559 ASSERT(args.length() == 2);
1560
1561 Object* receiver = args[0];
1562 Object* key = args[1];
1563 if (receiver->IsJSObject() &&
1564 key->IsString() &&
1565 !JSObject::cast(receiver)->HasFastProperties()) {
1566 Dictionary* dictionary = JSObject::cast(receiver)->property_dictionary();
1567 int entry = dictionary->FindStringEntry(String::cast(key));
1568 if ((entry != DescriptorArray::kNotFound)
1569 && (dictionary->DetailsAt(entry).type() == NORMAL)) {
1570 return dictionary->ValueAt(entry);
1571 }
1572 }
1573 return Runtime::GetObjectProperty(args.at<Object>(0),
1574 args.at<Object>(1));
1575}
1576
1577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578Object* Runtime::SetObjectProperty(Handle<Object> object,
1579 Handle<Object> key,
1580 Handle<Object> value,
1581 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001582 HandleScope scope;
1583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001585 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586 Handle<Object> error =
1587 Factory::NewTypeError("non_object_property_store",
1588 HandleVector(args, 2));
1589 return Top::Throw(*error);
1590 }
1591
1592 // If the object isn't a JavaScript object, we ignore the store.
1593 if (!object->IsJSObject()) return *value;
1594
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001595 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1596
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 // Check if the given key is an array index.
1598 uint32_t index;
1599 if (Array::IndexFromObject(*key, &index)) {
1600 ASSERT(attr == NONE);
1601
1602 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1603 // of a string using [] notation. We need to support this too in
1604 // JavaScript.
1605 // In the case of a String object we just need to redirect the assignment to
1606 // the underlying string if the index is in range. Since the underlying
1607 // string does nothing with the assignment then we can ignore such
1608 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001609 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001611 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001613 Handle<Object> result = SetElement(js_object, index, value);
1614 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 return *value;
1616 }
1617
1618 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001619 Handle<Object> result;
1620 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001622 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001624 Handle<String> key_string = Handle<String>::cast(key);
1625 key_string->TryFlatten();
1626 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001628 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 return *value;
1630 }
1631
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 bool has_pending_exception = false;
1634 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1635 if (has_pending_exception) return Failure::Exception();
1636 Handle<String> name = Handle<String>::cast(converted);
1637
1638 if (name->AsArrayIndex(&index)) {
1639 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001640 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001642 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 }
1644}
1645
1646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647static Object* Runtime_SetProperty(Arguments args) {
1648 NoHandleAllocation ha;
1649 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1650
1651 Handle<Object> object = args.at<Object>(0);
1652 Handle<Object> key = args.at<Object>(1);
1653 Handle<Object> value = args.at<Object>(2);
1654
1655 // Compute attributes.
1656 PropertyAttributes attributes = NONE;
1657 if (args.length() == 4) {
1658 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001659 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001660 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001661 RUNTIME_ASSERT(
1662 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1663 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664 }
1665 return Runtime::SetObjectProperty(object, key, value, attributes);
1666}
1667
1668
1669// Set a local property, even if it is READ_ONLY. If the property does not
1670// exist, it will be added with attributes NONE.
1671static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1672 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001673 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001674 CONVERT_CHECKED(JSObject, object, args[0]);
1675 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001676 // Compute attributes.
1677 PropertyAttributes attributes = NONE;
1678 if (args.length() == 4) {
1679 CONVERT_CHECKED(Smi, value_obj, args[3]);
1680 int unchecked_value = value_obj->value();
1681 // Only attribute bits should be set.
1682 RUNTIME_ASSERT(
1683 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1684 attributes = static_cast<PropertyAttributes>(unchecked_value);
1685 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001686
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001687 return object->
1688 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689}
1690
1691
1692static Object* Runtime_DeleteProperty(Arguments args) {
1693 NoHandleAllocation ha;
1694 ASSERT(args.length() == 2);
1695
1696 CONVERT_CHECKED(JSObject, object, args[0]);
1697 CONVERT_CHECKED(String, key, args[1]);
1698 return object->DeleteProperty(key);
1699}
1700
1701
1702static Object* Runtime_HasLocalProperty(Arguments args) {
1703 NoHandleAllocation ha;
1704 ASSERT(args.length() == 2);
1705 CONVERT_CHECKED(String, key, args[1]);
1706
1707 // Only JS objects can have properties.
1708 if (args[0]->IsJSObject()) {
1709 JSObject* object = JSObject::cast(args[0]);
1710 if (object->HasLocalProperty(key)) return Heap::true_value();
1711 } else if (args[0]->IsString()) {
1712 // Well, there is one exception: Handle [] on strings.
1713 uint32_t index;
1714 if (key->AsArrayIndex(&index)) {
1715 String* string = String::cast(args[0]);
1716 if (index < static_cast<uint32_t>(string->length()))
1717 return Heap::true_value();
1718 }
1719 }
1720 return Heap::false_value();
1721}
1722
1723
1724static Object* Runtime_HasProperty(Arguments args) {
1725 NoHandleAllocation na;
1726 ASSERT(args.length() == 2);
1727
1728 // Only JS objects can have properties.
1729 if (args[0]->IsJSObject()) {
1730 JSObject* object = JSObject::cast(args[0]);
1731 CONVERT_CHECKED(String, key, args[1]);
1732 if (object->HasProperty(key)) return Heap::true_value();
1733 }
1734 return Heap::false_value();
1735}
1736
1737
1738static Object* Runtime_HasElement(Arguments args) {
1739 NoHandleAllocation na;
1740 ASSERT(args.length() == 2);
1741
1742 // Only JS objects can have elements.
1743 if (args[0]->IsJSObject()) {
1744 JSObject* object = JSObject::cast(args[0]);
1745 CONVERT_CHECKED(Smi, index_obj, args[1]);
1746 uint32_t index = index_obj->value();
1747 if (object->HasElement(index)) return Heap::true_value();
1748 }
1749 return Heap::false_value();
1750}
1751
1752
1753static Object* Runtime_IsPropertyEnumerable(Arguments args) {
1754 NoHandleAllocation ha;
1755 ASSERT(args.length() == 2);
1756
1757 CONVERT_CHECKED(JSObject, object, args[0]);
1758 CONVERT_CHECKED(String, key, args[1]);
1759
1760 uint32_t index;
1761 if (key->AsArrayIndex(&index)) {
1762 return Heap::ToBoolean(object->HasElement(index));
1763 }
1764
1765 LookupResult result;
1766 object->LocalLookup(key, &result);
1767 if (!result.IsProperty()) return Heap::false_value();
1768 return Heap::ToBoolean(!result.IsDontEnum());
1769}
1770
1771
1772static Object* Runtime_GetPropertyNames(Arguments args) {
1773 HandleScope scope;
1774 ASSERT(args.length() == 1);
1775
1776 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1777 Handle<JSObject> object(raw_object);
1778 return *GetKeysFor(object);
1779}
1780
1781
1782// Returns either a FixedArray as Runtime_GetPropertyNames,
1783// or, if the given object has an enum cache that contains
1784// all enumerable properties of the object and its prototypes
1785// have none, the map of the object. This is used to speed up
1786// the check for deletions during a for-in.
1787static Object* Runtime_GetPropertyNamesFast(Arguments args) {
1788 ASSERT(args.length() == 1);
1789
1790 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1791
1792 if (raw_object->IsSimpleEnum()) return raw_object->map();
1793
1794 HandleScope scope;
1795 Handle<JSObject> object(raw_object);
1796 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
1797
1798 // Test again, since cache may have been built by preceding call.
1799 if (object->IsSimpleEnum()) return object->map();
1800
1801 return *content;
1802}
1803
1804
1805static Object* Runtime_GetArgumentsProperty(Arguments args) {
1806 NoHandleAllocation ha;
1807 ASSERT(args.length() == 1);
1808
1809 // Compute the frame holding the arguments.
1810 JavaScriptFrameIterator it;
1811 it.AdvanceToArgumentsFrame();
1812 JavaScriptFrame* frame = it.frame();
1813
1814 // Get the actual number of provided arguments.
1815 const uint32_t n = frame->GetProvidedParametersCount();
1816
1817 // Try to convert the key to an index. If successful and within
1818 // index return the the argument from the frame.
1819 uint32_t index;
1820 if (Array::IndexFromObject(args[0], &index) && index < n) {
1821 return frame->GetParameter(index);
1822 }
1823
1824 // Convert the key to a string.
1825 HandleScope scope;
1826 bool exception = false;
1827 Handle<Object> converted =
1828 Execution::ToString(args.at<Object>(0), &exception);
1829 if (exception) return Failure::Exception();
1830 Handle<String> key = Handle<String>::cast(converted);
1831
1832 // Try to convert the string key into an array index.
1833 if (key->AsArrayIndex(&index)) {
1834 if (index < n) {
1835 return frame->GetParameter(index);
1836 } else {
1837 return Top::initial_object_prototype()->GetElement(index);
1838 }
1839 }
1840
1841 // Handle special arguments properties.
1842 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
1843 if (key->Equals(Heap::callee_symbol())) return frame->function();
1844
1845 // Lookup in the initial Object.prototype object.
1846 return Top::initial_object_prototype()->GetProperty(*key);
1847}
1848
1849
1850static Object* Runtime_ToBool(Arguments args) {
1851 NoHandleAllocation ha;
1852 ASSERT(args.length() == 1);
1853
1854 return args[0]->ToBoolean();
1855}
1856
1857
1858// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
1859// Possible optimizations: put the type string into the oddballs.
1860static Object* Runtime_Typeof(Arguments args) {
1861 NoHandleAllocation ha;
1862
1863 Object* obj = args[0];
1864 if (obj->IsNumber()) return Heap::number_symbol();
1865 HeapObject* heap_obj = HeapObject::cast(obj);
1866
1867 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001868 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869
1870 InstanceType instance_type = heap_obj->map()->instance_type();
1871 if (instance_type < FIRST_NONSTRING_TYPE) {
1872 return Heap::string_symbol();
1873 }
1874
1875 switch (instance_type) {
1876 case ODDBALL_TYPE:
1877 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
1878 return Heap::boolean_symbol();
1879 }
1880 if (heap_obj->IsNull()) {
1881 return Heap::object_symbol();
1882 }
1883 ASSERT(heap_obj->IsUndefined());
1884 return Heap::undefined_symbol();
1885 case JS_FUNCTION_TYPE:
1886 return Heap::function_symbol();
1887 default:
1888 // For any kind of object not handled above, the spec rule for
1889 // host objects gives that it is okay to return "object"
1890 return Heap::object_symbol();
1891 }
1892}
1893
1894
1895static Object* Runtime_StringToNumber(Arguments args) {
1896 NoHandleAllocation ha;
1897 ASSERT(args.length() == 1);
1898 CONVERT_CHECKED(String, subject, args[0]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001899 subject->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
1901}
1902
1903
1904static Object* Runtime_StringFromCharCodeArray(Arguments args) {
1905 NoHandleAllocation ha;
1906 ASSERT(args.length() == 1);
1907
1908 CONVERT_CHECKED(JSArray, codes, args[0]);
1909 int length = Smi::cast(codes->length())->value();
1910
1911 // Check if the string can be ASCII.
1912 int i;
1913 for (i = 0; i < length; i++) {
1914 Object* element = codes->GetElement(i);
1915 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
1916 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
1917 break;
1918 }
1919
1920 Object* object = NULL;
1921 if (i == length) { // The string is ASCII.
1922 object = Heap::AllocateRawAsciiString(length);
1923 } else { // The string is not ASCII.
1924 object = Heap::AllocateRawTwoByteString(length);
1925 }
1926
1927 if (object->IsFailure()) return object;
1928 String* result = String::cast(object);
1929 for (int i = 0; i < length; i++) {
1930 Object* element = codes->GetElement(i);
1931 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
1932 result->Set(i, chr & 0xffff);
1933 }
1934 return result;
1935}
1936
1937
1938// kNotEscaped is generated by the following:
1939//
1940// #!/bin/perl
1941// for (my $i = 0; $i < 256; $i++) {
1942// print "\n" if $i % 16 == 0;
1943// my $c = chr($i);
1944// my $escaped = 1;
1945// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
1946// print $escaped ? "0, " : "1, ";
1947// }
1948
1949
1950static bool IsNotEscaped(uint16_t character) {
1951 // Only for 8 bit characters, the rest are always escaped (in a different way)
1952 ASSERT(character < 256);
1953 static const char kNotEscaped[256] = {
1954 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1955 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1956 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
1957 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
1958 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1959 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1960 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1961 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1962 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1963 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1964 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1965 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1966 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1967 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1968 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1969 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1970 };
1971 return kNotEscaped[character] != 0;
1972}
1973
1974
1975static Object* Runtime_URIEscape(Arguments args) {
1976 const char hex_chars[] = "0123456789ABCDEF";
1977 NoHandleAllocation ha;
1978 ASSERT(args.length() == 1);
1979 CONVERT_CHECKED(String, source, args[0]);
1980
1981 source->TryFlatten();
1982
1983 int escaped_length = 0;
1984 int length = source->length();
1985 {
1986 Access<StringInputBuffer> buffer(&string_input_buffer);
1987 buffer->Reset(source);
1988 while (buffer->has_more()) {
1989 uint16_t character = buffer->GetNext();
1990 if (character >= 256) {
1991 escaped_length += 6;
1992 } else if (IsNotEscaped(character)) {
1993 escaped_length++;
1994 } else {
1995 escaped_length += 3;
1996 }
1997 // We don't allow strings that are longer than Smi range.
1998 if (!Smi::IsValid(escaped_length)) {
1999 Top::context()->mark_out_of_memory();
2000 return Failure::OutOfMemoryException();
2001 }
2002 }
2003 }
2004 // No length change implies no change. Return original string if no change.
2005 if (escaped_length == length) {
2006 return source;
2007 }
2008 Object* o = Heap::AllocateRawAsciiString(escaped_length);
2009 if (o->IsFailure()) return o;
2010 String* destination = String::cast(o);
2011 int dest_position = 0;
2012
2013 Access<StringInputBuffer> buffer(&string_input_buffer);
2014 buffer->Rewind();
2015 while (buffer->has_more()) {
2016 uint16_t character = buffer->GetNext();
2017 if (character >= 256) {
2018 destination->Set(dest_position, '%');
2019 destination->Set(dest_position+1, 'u');
2020 destination->Set(dest_position+2, hex_chars[character >> 12]);
2021 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
2022 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
2023 destination->Set(dest_position+5, hex_chars[character & 0xf]);
2024 dest_position += 6;
2025 } else if (IsNotEscaped(character)) {
2026 destination->Set(dest_position, character);
2027 dest_position++;
2028 } else {
2029 destination->Set(dest_position, '%');
2030 destination->Set(dest_position+1, hex_chars[character >> 4]);
2031 destination->Set(dest_position+2, hex_chars[character & 0xf]);
2032 dest_position += 3;
2033 }
2034 }
2035 return destination;
2036}
2037
2038
2039static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
2040 static const signed char kHexValue['g'] = {
2041 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2042 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2043 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2044 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
2045 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2046 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2047 -1, 10, 11, 12, 13, 14, 15 };
2048
2049 if (character1 > 'f') return -1;
2050 int hi = kHexValue[character1];
2051 if (hi == -1) return -1;
2052 if (character2 > 'f') return -1;
2053 int lo = kHexValue[character2];
2054 if (lo == -1) return -1;
2055 return (hi << 4) + lo;
2056}
2057
2058
2059static inline int Unescape(String* source, int i, int length, int* step) {
2060 uint16_t character = source->Get(i);
2061 int32_t hi, lo;
2062 if (character == '%' &&
2063 i <= length - 6 &&
2064 source->Get(i + 1) == 'u' &&
2065 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
2066 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
2067 *step = 6;
2068 return (hi << 8) + lo;
2069 } else if (character == '%' &&
2070 i <= length - 3 &&
2071 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
2072 *step = 3;
2073 return lo;
2074 } else {
2075 *step = 1;
2076 return character;
2077 }
2078}
2079
2080
2081static Object* Runtime_URIUnescape(Arguments args) {
2082 NoHandleAllocation ha;
2083 ASSERT(args.length() == 1);
2084 CONVERT_CHECKED(String, source, args[0]);
2085
2086 source->TryFlatten();
2087
2088 bool ascii = true;
2089 int length = source->length();
2090
2091 int unescaped_length = 0;
2092 for (int i = 0; i < length; unescaped_length++) {
2093 int step;
2094 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
2095 ascii = false;
2096 i += step;
2097 }
2098
2099 // No length change implies no change. Return original string if no change.
2100 if (unescaped_length == length)
2101 return source;
2102
2103 Object* o = ascii ?
2104 Heap::AllocateRawAsciiString(unescaped_length) :
2105 Heap::AllocateRawTwoByteString(unescaped_length);
2106 if (o->IsFailure()) return o;
2107 String* destination = String::cast(o);
2108
2109 int dest_position = 0;
2110 for (int i = 0; i < length; dest_position++) {
2111 int step;
2112 destination->Set(dest_position, Unescape(source, i, length, &step));
2113 i += step;
2114 }
2115 return destination;
2116}
2117
2118
2119static Object* Runtime_StringParseInt(Arguments args) {
2120 NoHandleAllocation ha;
2121
2122 CONVERT_CHECKED(String, s, args[0]);
2123 CONVERT_DOUBLE_CHECKED(n, args[1]);
2124 int radix = FastD2I(n);
2125
2126 s->TryFlatten();
2127
2128 int len = s->length();
2129 int i;
2130
2131 // Skip leading white space.
2132 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
2133 if (i == len) return Heap::nan_value();
2134
2135 // Compute the sign (default to +).
2136 int sign = 1;
2137 if (s->Get(i) == '-') {
2138 sign = -1;
2139 i++;
2140 } else if (s->Get(i) == '+') {
2141 i++;
2142 }
2143
2144 // Compute the radix if 0.
2145 if (radix == 0) {
2146 radix = 10;
2147 if (i < len && s->Get(i) == '0') {
2148 radix = 8;
2149 if (i + 1 < len) {
2150 int c = s->Get(i + 1);
2151 if (c == 'x' || c == 'X') {
2152 radix = 16;
2153 i += 2;
2154 }
2155 }
2156 }
2157 } else if (radix == 16) {
2158 // Allow 0x or 0X prefix if radix is 16.
2159 if (i + 1 < len && s->Get(i) == '0') {
2160 int c = s->Get(i + 1);
2161 if (c == 'x' || c == 'X') i += 2;
2162 }
2163 }
2164
2165 RUNTIME_ASSERT(2 <= radix && radix <= 36);
2166 double value;
2167 int end_index = StringToInt(s, i, radix, &value);
2168 if (end_index != i) {
2169 return Heap::NumberFromDouble(sign * value);
2170 }
2171 return Heap::nan_value();
2172}
2173
2174
2175static Object* Runtime_StringParseFloat(Arguments args) {
2176 NoHandleAllocation ha;
2177 CONVERT_CHECKED(String, str, args[0]);
2178
2179 // ECMA-262 section 15.1.2.3, empty string is NaN
2180 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
2181
2182 // Create a number object from the value.
2183 return Heap::NumberFromDouble(value);
2184}
2185
2186
2187static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
2188static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
2189
2190
2191template <class Converter>
2192static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002193 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002194 NoHandleAllocation ha;
2195
2196 CONVERT_CHECKED(String, s, args[0]);
2197 int raw_string_length = s->length();
2198 // Assume that the string is not empty; we need this assumption later
2199 if (raw_string_length == 0) return s;
2200 int length = raw_string_length;
2201
2202 s->TryFlatten();
2203
2204 // We try this twice, once with the assumption that the result is
2205 // no longer than the input and, if that assumption breaks, again
2206 // with the exact length. This is implemented using a goto back
2207 // to this label if we discover that the assumption doesn't hold.
2208 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00002209 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002210 try_convert:
2211
2212 // Allocate the resulting string.
2213 //
2214 // NOTE: This assumes that the upper/lower case of an ascii
2215 // character is also ascii. This is currently the case, but it
2216 // might break in the future if we implement more context and locale
2217 // dependent upper/lower conversions.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002218 Object* o = s->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002219 ? Heap::AllocateRawAsciiString(length)
2220 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002221 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002222 String* result = String::cast(o);
2223 bool has_changed_character = false;
2224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002225 // Convert all characters to upper case, assuming that they will fit
2226 // in the buffer
2227 Access<StringInputBuffer> buffer(&string_input_buffer);
2228 buffer->Reset(s);
2229 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
2230 int i = 0;
2231 // We can assume that the string is not empty
2232 uc32 current = buffer->GetNext();
2233 while (i < length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002234 bool has_next = buffer->has_more();
2235 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002236 int char_length = mapping->get(current, next, chars);
2237 if (char_length == 0) {
2238 // The case conversion of this character is the character itself.
2239 result->Set(i, current);
2240 i++;
2241 } else if (char_length == 1) {
2242 // Common case: converting the letter resulted in one character.
2243 ASSERT(static_cast<uc32>(chars[0]) != current);
2244 result->Set(i, chars[0]);
2245 has_changed_character = true;
2246 i++;
2247 } else if (length == raw_string_length) {
2248 // We've assumed that the result would be as long as the
2249 // input but here is a character that converts to several
2250 // characters. No matter, we calculate the exact length
2251 // of the result and try the whole thing again.
2252 //
2253 // Note that this leaves room for optimization. We could just
2254 // memcpy what we already have to the result string. Also,
2255 // the result string is the last object allocated we could
2256 // "realloc" it and probably, in the vast majority of cases,
2257 // extend the existing string to be able to hold the full
2258 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002259 int next_length = 0;
2260 if (has_next) {
2261 next_length = mapping->get(next, 0, chars);
2262 if (next_length == 0) next_length = 1;
2263 }
2264 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002265 while (buffer->has_more()) {
2266 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002267 // NOTE: we use 0 as the next character here because, while
2268 // the next character may affect what a character converts to,
2269 // it does not in any case affect the length of what it convert
2270 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 int char_length = mapping->get(current, 0, chars);
2272 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002273 current_length += char_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002274 }
2275 length = current_length;
2276 goto try_convert;
2277 } else {
2278 for (int j = 0; j < char_length; j++) {
2279 result->Set(i, chars[j]);
2280 i++;
2281 }
2282 has_changed_character = true;
2283 }
2284 current = next;
2285 }
2286 if (has_changed_character) {
2287 return result;
2288 } else {
2289 // If we didn't actually change anything in doing the conversion
2290 // we simple return the result and let the converted string
2291 // become garbage; there is no reason to keep two identical strings
2292 // alive.
2293 return s;
2294 }
2295}
2296
2297
2298static Object* Runtime_StringToLowerCase(Arguments args) {
2299 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
2300}
2301
2302
2303static Object* Runtime_StringToUpperCase(Arguments args) {
2304 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
2305}
2306
2307
2308static Object* Runtime_ConsStringFst(Arguments args) {
2309 NoHandleAllocation ha;
2310
2311 CONVERT_CHECKED(ConsString, str, args[0]);
2312 return str->first();
2313}
2314
2315
2316static Object* Runtime_ConsStringSnd(Arguments args) {
2317 NoHandleAllocation ha;
2318
2319 CONVERT_CHECKED(ConsString, str, args[0]);
2320 return str->second();
2321}
2322
2323
2324static Object* Runtime_NumberToString(Arguments args) {
2325 NoHandleAllocation ha;
2326 ASSERT(args.length() == 1);
2327
2328 Object* number = args[0];
2329 RUNTIME_ASSERT(number->IsNumber());
2330
2331 Object* cached = Heap::GetNumberStringCache(number);
2332 if (cached != Heap::undefined_value()) {
2333 return cached;
2334 }
2335
2336 char arr[100];
2337 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2338 const char* str;
2339 if (number->IsSmi()) {
2340 int num = Smi::cast(number)->value();
2341 str = IntToCString(num, buffer);
2342 } else {
2343 double num = HeapNumber::cast(number)->value();
2344 str = DoubleToCString(num, buffer);
2345 }
2346 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2347
2348 if (!result->IsFailure()) {
2349 Heap::SetNumberStringCache(number, String::cast(result));
2350 }
2351 return result;
2352}
2353
2354
2355static Object* Runtime_NumberToInteger(Arguments args) {
2356 NoHandleAllocation ha;
2357 ASSERT(args.length() == 1);
2358
2359 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002360 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002361 CONVERT_DOUBLE_CHECKED(number, obj);
2362 return Heap::NumberFromDouble(DoubleToInteger(number));
2363}
2364
2365
2366static Object* Runtime_NumberToJSUint32(Arguments args) {
2367 NoHandleAllocation ha;
2368 ASSERT(args.length() == 1);
2369
2370 Object* obj = args[0];
2371 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2372 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2373 return Heap::NumberFromUint32(number);
2374}
2375
2376
2377static Object* Runtime_NumberToJSInt32(Arguments args) {
2378 NoHandleAllocation ha;
2379 ASSERT(args.length() == 1);
2380
2381 Object* obj = args[0];
2382 if (obj->IsSmi()) return obj;
2383 CONVERT_DOUBLE_CHECKED(number, obj);
2384 return Heap::NumberFromInt32(DoubleToInt32(number));
2385}
2386
2387
2388static Object* Runtime_NumberAdd(Arguments args) {
2389 NoHandleAllocation ha;
2390 ASSERT(args.length() == 2);
2391
2392 CONVERT_DOUBLE_CHECKED(x, args[0]);
2393 CONVERT_DOUBLE_CHECKED(y, args[1]);
2394 return Heap::AllocateHeapNumber(x + y);
2395}
2396
2397
2398static Object* Runtime_NumberSub(Arguments args) {
2399 NoHandleAllocation ha;
2400 ASSERT(args.length() == 2);
2401
2402 CONVERT_DOUBLE_CHECKED(x, args[0]);
2403 CONVERT_DOUBLE_CHECKED(y, args[1]);
2404 return Heap::AllocateHeapNumber(x - y);
2405}
2406
2407
2408static Object* Runtime_NumberMul(Arguments args) {
2409 NoHandleAllocation ha;
2410 ASSERT(args.length() == 2);
2411
2412 CONVERT_DOUBLE_CHECKED(x, args[0]);
2413 CONVERT_DOUBLE_CHECKED(y, args[1]);
2414 return Heap::AllocateHeapNumber(x * y);
2415}
2416
2417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002418static Object* Runtime_NumberUnaryMinus(Arguments args) {
2419 NoHandleAllocation ha;
2420 ASSERT(args.length() == 1);
2421
2422 CONVERT_DOUBLE_CHECKED(x, args[0]);
2423 return Heap::AllocateHeapNumber(-x);
2424}
2425
2426
2427static Object* Runtime_NumberDiv(Arguments args) {
2428 NoHandleAllocation ha;
2429 ASSERT(args.length() == 2);
2430
2431 CONVERT_DOUBLE_CHECKED(x, args[0]);
2432 CONVERT_DOUBLE_CHECKED(y, args[1]);
2433 return Heap::NewNumberFromDouble(x / y);
2434}
2435
2436
2437static Object* Runtime_NumberMod(Arguments args) {
2438 NoHandleAllocation ha;
2439 ASSERT(args.length() == 2);
2440
2441 CONVERT_DOUBLE_CHECKED(x, args[0]);
2442 CONVERT_DOUBLE_CHECKED(y, args[1]);
2443
2444#ifdef WIN32
2445 // Workaround MS fmod bugs. ECMA-262 says:
2446 // dividend is finite and divisor is an infinity => result equals dividend
2447 // dividend is a zero and divisor is nonzero finite => result equals dividend
2448 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2449 !(x == 0 && (y != 0 && isfinite(y))))
2450#endif
2451 x = fmod(x, y);
2452 // NewNumberFromDouble may return a Smi instead of a Number object
2453 return Heap::NewNumberFromDouble(x);
2454}
2455
2456
2457static Object* Runtime_StringAdd(Arguments args) {
2458 NoHandleAllocation ha;
2459 ASSERT(args.length() == 2);
2460
2461 CONVERT_CHECKED(String, str1, args[0]);
2462 CONVERT_CHECKED(String, str2, args[1]);
2463 int len1 = str1->length();
2464 int len2 = str2->length();
2465 if (len1 == 0) return str2;
2466 if (len2 == 0) return str1;
2467 int length_sum = len1 + len2;
2468 // Make sure that an out of memory exception is thrown if the length
2469 // of the new cons string is too large to fit in a Smi.
2470 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2471 Top::context()->mark_out_of_memory();
2472 return Failure::OutOfMemoryException();
2473 }
2474 return Heap::AllocateConsString(str1, str2);
2475}
2476
2477
2478static Object* Runtime_StringBuilderConcat(Arguments args) {
2479 NoHandleAllocation ha;
2480 ASSERT(args.length() == 2);
2481 CONVERT_CHECKED(JSArray, array, args[0]);
2482 CONVERT_CHECKED(String, special, args[1]);
2483 int special_length = special->length();
2484 Object* smi_array_length = array->length();
2485 if (!smi_array_length->IsSmi()) {
2486 Top::context()->mark_out_of_memory();
2487 return Failure::OutOfMemoryException();
2488 }
2489 int array_length = Smi::cast(smi_array_length)->value();
2490 if (!array->HasFastElements()) {
2491 return Top::Throw(Heap::illegal_argument_symbol());
2492 }
2493 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002494 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002495 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002496 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002497
2498 if (array_length == 0) {
2499 return Heap::empty_string();
2500 } else if (array_length == 1) {
2501 Object* first = fixed_array->get(0);
2502 if (first->IsString()) return first;
2503 }
2504
ager@chromium.org7c537e22008-10-16 08:43:32 +00002505 bool ascii = special->IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002506 int position = 0;
2507 for (int i = 0; i < array_length; i++) {
2508 Object* elt = fixed_array->get(i);
2509 if (elt->IsSmi()) {
2510 int len = Smi::cast(elt)->value();
2511 int pos = len >> 11;
2512 len &= 0x7ff;
2513 if (pos + len > special_length) {
2514 return Top::Throw(Heap::illegal_argument_symbol());
2515 }
2516 position += len;
2517 } else if (elt->IsString()) {
2518 String* element = String::cast(elt);
2519 int element_length = element->length();
2520 if (!Smi::IsValid(element_length + position)) {
2521 Top::context()->mark_out_of_memory();
2522 return Failure::OutOfMemoryException();
2523 }
2524 position += element_length;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002525 if (ascii && !element->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002526 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002527 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002528 } else {
2529 return Top::Throw(Heap::illegal_argument_symbol());
2530 }
2531 }
2532
2533 int length = position;
2534 position = 0;
2535 Object* object;
2536 if (ascii) {
2537 object = Heap::AllocateRawAsciiString(length);
2538 } else {
2539 object = Heap::AllocateRawTwoByteString(length);
2540 }
2541 if (object->IsFailure()) return object;
2542
2543 String* answer = String::cast(object);
2544 for (int i = 0; i < array_length; i++) {
2545 Object* element = fixed_array->get(i);
2546 if (element->IsSmi()) {
2547 int len = Smi::cast(element)->value();
2548 int pos = len >> 11;
2549 len &= 0x7ff;
2550 String::Flatten(special, answer, pos, pos + len, position);
2551 position += len;
2552 } else {
2553 String* string = String::cast(element);
2554 int element_length = string->length();
2555 String::Flatten(string, answer, 0, element_length, position);
2556 position += element_length;
2557 }
2558 }
2559 return answer;
2560}
2561
2562
2563static Object* Runtime_NumberOr(Arguments args) {
2564 NoHandleAllocation ha;
2565 ASSERT(args.length() == 2);
2566
2567 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2568 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2569 return Heap::NumberFromInt32(x | y);
2570}
2571
2572
2573static Object* Runtime_NumberAnd(Arguments args) {
2574 NoHandleAllocation ha;
2575 ASSERT(args.length() == 2);
2576
2577 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2578 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2579 return Heap::NumberFromInt32(x & y);
2580}
2581
2582
2583static Object* Runtime_NumberXor(Arguments args) {
2584 NoHandleAllocation ha;
2585 ASSERT(args.length() == 2);
2586
2587 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2588 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2589 return Heap::NumberFromInt32(x ^ y);
2590}
2591
2592
2593static Object* Runtime_NumberNot(Arguments args) {
2594 NoHandleAllocation ha;
2595 ASSERT(args.length() == 1);
2596
2597 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2598 return Heap::NumberFromInt32(~x);
2599}
2600
2601
2602static Object* Runtime_NumberShl(Arguments args) {
2603 NoHandleAllocation ha;
2604 ASSERT(args.length() == 2);
2605
2606 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2607 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2608 return Heap::NumberFromInt32(x << (y & 0x1f));
2609}
2610
2611
2612static Object* Runtime_NumberShr(Arguments args) {
2613 NoHandleAllocation ha;
2614 ASSERT(args.length() == 2);
2615
2616 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2617 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2618 return Heap::NumberFromUint32(x >> (y & 0x1f));
2619}
2620
2621
2622static Object* Runtime_NumberSar(Arguments args) {
2623 NoHandleAllocation ha;
2624 ASSERT(args.length() == 2);
2625
2626 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2627 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2628 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2629}
2630
2631
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002632static Object* Runtime_NumberEquals(Arguments args) {
2633 NoHandleAllocation ha;
2634 ASSERT(args.length() == 2);
2635
2636 CONVERT_DOUBLE_CHECKED(x, args[0]);
2637 CONVERT_DOUBLE_CHECKED(y, args[1]);
2638 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
2639 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
2640 if (x == y) return Smi::FromInt(EQUAL);
2641 Object* result;
2642 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
2643 result = Smi::FromInt(EQUAL);
2644 } else {
2645 result = Smi::FromInt(NOT_EQUAL);
2646 }
2647 return result;
2648}
2649
2650
2651static Object* Runtime_StringEquals(Arguments args) {
2652 NoHandleAllocation ha;
2653 ASSERT(args.length() == 2);
2654
2655 CONVERT_CHECKED(String, x, args[0]);
2656 CONVERT_CHECKED(String, y, args[1]);
2657
2658 // This is very similar to String::Equals(String*) but that version
2659 // requires flattened strings as input, whereas we flatten the
2660 // strings only if the fast cases fail. Note that this may fail,
2661 // requiring a GC. String::Equals(String*) returns a bool and has
2662 // no way to signal a failure.
2663 if (y == x) return Smi::FromInt(EQUAL);
2664 if (x->IsSymbol() && y->IsSymbol()) return Smi::FromInt(NOT_EQUAL);
2665 // Compare contents
2666 int len = x->length();
2667 if (len != y->length()) return Smi::FromInt(NOT_EQUAL);
2668 if (len == 0) return Smi::FromInt(EQUAL);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002669
2670 // Handle one elment strings.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002671 if (x->Get(0) != y->Get(0)) return Smi::FromInt(NOT_EQUAL);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002672 if (len == 1) return Smi::FromInt(EQUAL);
2673
2674 // Fast case: First, middle and last characters.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002675 if (x->Get(len>>1) != y->Get(len>>1)) return Smi::FromInt(NOT_EQUAL);
2676 if (x->Get(len - 1) != y->Get(len - 1)) return Smi::FromInt(NOT_EQUAL);
2677
2678 x->TryFlatten();
2679 y->TryFlatten();
2680
2681 static StringInputBuffer buf1;
2682 static StringInputBuffer buf2;
2683 buf1.Reset(x);
2684 buf2.Reset(y);
2685 while (buf1.has_more()) {
2686 if (buf1.GetNext() != buf2.GetNext())
2687 return Smi::FromInt(NOT_EQUAL);
2688 }
2689 return Smi::FromInt(EQUAL);
2690}
2691
2692
2693static Object* Runtime_NumberCompare(Arguments args) {
2694 NoHandleAllocation ha;
2695 ASSERT(args.length() == 3);
2696
2697 CONVERT_DOUBLE_CHECKED(x, args[0]);
2698 CONVERT_DOUBLE_CHECKED(y, args[1]);
2699 if (isnan(x) || isnan(y)) return args[2];
2700 if (x == y) return Smi::FromInt(EQUAL);
2701 if (isless(x, y)) return Smi::FromInt(LESS);
2702 return Smi::FromInt(GREATER);
2703}
2704
2705
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002706// Compare two Smis as if they were converted to strings and then
2707// compared lexicographically.
2708static Object* Runtime_SmiLexicographicCompare(Arguments args) {
2709 NoHandleAllocation ha;
2710 ASSERT(args.length() == 2);
2711
2712 // Arrays for the individual characters of the two Smis. Smis are
2713 // 31 bit integers and 10 decimal digits are therefore enough.
2714 static int x_elms[10];
2715 static int y_elms[10];
2716
2717 // Extract the integer values from the Smis.
2718 CONVERT_CHECKED(Smi, x, args[0]);
2719 CONVERT_CHECKED(Smi, y, args[1]);
2720 int x_value = x->value();
2721 int y_value = y->value();
2722
2723 // If the integers are equal so are the string representations.
2724 if (x_value == y_value) return Smi::FromInt(EQUAL);
2725
2726 // If one of the integers are zero the normal integer order is the
2727 // same as the lexicographic order of the string representations.
2728 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
2729
2730 // If only one of the intergers is negative the negative number is
2731 // smallest because the char code of '-' is less than the char code
2732 // of any digit. Otherwise, we make both values positive.
2733 if (x_value < 0 || y_value < 0) {
2734 if (y_value >= 0) return Smi::FromInt(LESS);
2735 if (x_value >= 0) return Smi::FromInt(GREATER);
2736 x_value = -x_value;
2737 y_value = -y_value;
2738 }
2739
2740 // Convert the integers to arrays of their decimal digits.
2741 int x_index = 0;
2742 int y_index = 0;
2743 while (x_value > 0) {
2744 x_elms[x_index++] = x_value % 10;
2745 x_value /= 10;
2746 }
2747 while (y_value > 0) {
2748 y_elms[y_index++] = y_value % 10;
2749 y_value /= 10;
2750 }
2751
2752 // Loop through the arrays of decimal digits finding the first place
2753 // where they differ.
2754 while (--x_index >= 0 && --y_index >= 0) {
2755 int diff = x_elms[x_index] - y_elms[y_index];
2756 if (diff != 0) return Smi::FromInt(diff);
2757 }
2758
2759 // If one array is a suffix of the other array, the longest array is
2760 // the representation of the largest of the Smis in the
2761 // lexicographic ordering.
2762 return Smi::FromInt(x_index - y_index);
2763}
2764
2765
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002766static Object* Runtime_StringCompare(Arguments args) {
2767 NoHandleAllocation ha;
2768 ASSERT(args.length() == 2);
2769
2770 CONVERT_CHECKED(String, x, args[0]);
2771 CONVERT_CHECKED(String, y, args[1]);
2772
2773 // A few fast case tests before we flatten.
2774 if (x == y) return Smi::FromInt(EQUAL);
2775 if (y->length() == 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002776 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002777 return Smi::FromInt(GREATER);
2778 } else if (x->length() == 0) {
2779 return Smi::FromInt(LESS);
2780 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002781
2782 int d = x->Get(0) - y->Get(0);
2783 if (d < 0) return Smi::FromInt(LESS);
2784 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002785
2786 x->TryFlatten();
2787 y->TryFlatten();
2788
2789 static StringInputBuffer bufx;
2790 static StringInputBuffer bufy;
2791 bufx.Reset(x);
2792 bufy.Reset(y);
2793 while (bufx.has_more() && bufy.has_more()) {
2794 int d = bufx.GetNext() - bufy.GetNext();
2795 if (d < 0) return Smi::FromInt(LESS);
2796 else if (d > 0) return Smi::FromInt(GREATER);
2797 }
2798
2799 // x is (non-trivial) prefix of y:
2800 if (bufy.has_more()) return Smi::FromInt(LESS);
2801 // y is prefix of x:
2802 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
2803}
2804
2805
2806static Object* Runtime_Math_abs(Arguments args) {
2807 NoHandleAllocation ha;
2808 ASSERT(args.length() == 1);
2809
2810 CONVERT_DOUBLE_CHECKED(x, args[0]);
2811 return Heap::AllocateHeapNumber(fabs(x));
2812}
2813
2814
2815static Object* Runtime_Math_acos(Arguments args) {
2816 NoHandleAllocation ha;
2817 ASSERT(args.length() == 1);
2818
2819 CONVERT_DOUBLE_CHECKED(x, args[0]);
2820 return Heap::AllocateHeapNumber(acos(x));
2821}
2822
2823
2824static Object* Runtime_Math_asin(Arguments args) {
2825 NoHandleAllocation ha;
2826 ASSERT(args.length() == 1);
2827
2828 CONVERT_DOUBLE_CHECKED(x, args[0]);
2829 return Heap::AllocateHeapNumber(asin(x));
2830}
2831
2832
2833static Object* Runtime_Math_atan(Arguments args) {
2834 NoHandleAllocation ha;
2835 ASSERT(args.length() == 1);
2836
2837 CONVERT_DOUBLE_CHECKED(x, args[0]);
2838 return Heap::AllocateHeapNumber(atan(x));
2839}
2840
2841
2842static Object* Runtime_Math_atan2(Arguments args) {
2843 NoHandleAllocation ha;
2844 ASSERT(args.length() == 2);
2845
2846 CONVERT_DOUBLE_CHECKED(x, args[0]);
2847 CONVERT_DOUBLE_CHECKED(y, args[1]);
2848 double result;
2849 if (isinf(x) && isinf(y)) {
2850 // Make sure that the result in case of two infinite arguments
2851 // is a multiple of Pi / 4. The sign of the result is determined
2852 // by the first argument (x) and the sign of the second argument
2853 // determines the multiplier: one or three.
2854 static double kPiDividedBy4 = 0.78539816339744830962;
2855 int multiplier = (x < 0) ? -1 : 1;
2856 if (y < 0) multiplier *= 3;
2857 result = multiplier * kPiDividedBy4;
2858 } else {
2859 result = atan2(x, y);
2860 }
2861 return Heap::AllocateHeapNumber(result);
2862}
2863
2864
2865static Object* Runtime_Math_ceil(Arguments args) {
2866 NoHandleAllocation ha;
2867 ASSERT(args.length() == 1);
2868
2869 CONVERT_DOUBLE_CHECKED(x, args[0]);
2870 return Heap::NumberFromDouble(ceiling(x));
2871}
2872
2873
2874static Object* Runtime_Math_cos(Arguments args) {
2875 NoHandleAllocation ha;
2876 ASSERT(args.length() == 1);
2877
2878 CONVERT_DOUBLE_CHECKED(x, args[0]);
2879 return Heap::AllocateHeapNumber(cos(x));
2880}
2881
2882
2883static Object* Runtime_Math_exp(Arguments args) {
2884 NoHandleAllocation ha;
2885 ASSERT(args.length() == 1);
2886
2887 CONVERT_DOUBLE_CHECKED(x, args[0]);
2888 return Heap::AllocateHeapNumber(exp(x));
2889}
2890
2891
2892static Object* Runtime_Math_floor(Arguments args) {
2893 NoHandleAllocation ha;
2894 ASSERT(args.length() == 1);
2895
2896 CONVERT_DOUBLE_CHECKED(x, args[0]);
2897 return Heap::NumberFromDouble(floor(x));
2898}
2899
2900
2901static Object* Runtime_Math_log(Arguments args) {
2902 NoHandleAllocation ha;
2903 ASSERT(args.length() == 1);
2904
2905 CONVERT_DOUBLE_CHECKED(x, args[0]);
2906 return Heap::AllocateHeapNumber(log(x));
2907}
2908
2909
2910static Object* Runtime_Math_pow(Arguments args) {
2911 NoHandleAllocation ha;
2912 ASSERT(args.length() == 2);
2913
2914 CONVERT_DOUBLE_CHECKED(x, args[0]);
2915 CONVERT_DOUBLE_CHECKED(y, args[1]);
2916 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
2917 return Heap::nan_value();
2918 } else if (y == 0) {
2919 return Smi::FromInt(1);
2920 } else {
2921 return Heap::AllocateHeapNumber(pow(x, y));
2922 }
2923}
2924
2925// Returns a number value with positive sign, greater than or equal to
2926// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00002927static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002928 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00002929 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930
2931 // To get much better precision, we combine the results of two
2932 // invocations of random(). The result is computed by normalizing a
2933 // double in the range [0, RAND_MAX + 1) obtained by adding the
2934 // high-order bits in the range [0, RAND_MAX] with the low-order
2935 // bits in the range [0, 1).
2936 double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
2937 double hi = static_cast<double>(random());
2938 double result = (hi + lo) / (RAND_MAX + 1.0);
2939 ASSERT(result >= 0 && result < 1);
2940 return Heap::AllocateHeapNumber(result);
2941}
2942
2943
2944static Object* Runtime_Math_round(Arguments args) {
2945 NoHandleAllocation ha;
2946 ASSERT(args.length() == 1);
2947
2948 CONVERT_DOUBLE_CHECKED(x, args[0]);
2949 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
2950 return Heap::NumberFromDouble(floor(x + 0.5));
2951}
2952
2953
2954static Object* Runtime_Math_sin(Arguments args) {
2955 NoHandleAllocation ha;
2956 ASSERT(args.length() == 1);
2957
2958 CONVERT_DOUBLE_CHECKED(x, args[0]);
2959 return Heap::AllocateHeapNumber(sin(x));
2960}
2961
2962
2963static Object* Runtime_Math_sqrt(Arguments args) {
2964 NoHandleAllocation ha;
2965 ASSERT(args.length() == 1);
2966
2967 CONVERT_DOUBLE_CHECKED(x, args[0]);
2968 return Heap::AllocateHeapNumber(sqrt(x));
2969}
2970
2971
2972static Object* Runtime_Math_tan(Arguments args) {
2973 NoHandleAllocation ha;
2974 ASSERT(args.length() == 1);
2975
2976 CONVERT_DOUBLE_CHECKED(x, args[0]);
2977 return Heap::AllocateHeapNumber(tan(x));
2978}
2979
2980
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002981// The NewArguments function is only used when constructing the
2982// arguments array when calling non-functions from JavaScript in
2983// runtime.js:CALL_NON_FUNCTION.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984static Object* Runtime_NewArguments(Arguments args) {
2985 NoHandleAllocation ha;
2986 ASSERT(args.length() == 1);
2987
2988 // ECMA-262, 3rd., 10.1.8, p.39
2989 CONVERT_CHECKED(JSFunction, callee, args[0]);
2990
2991 // Compute the frame holding the arguments.
2992 JavaScriptFrameIterator it;
2993 it.AdvanceToArgumentsFrame();
2994 JavaScriptFrame* frame = it.frame();
2995
2996 const int length = frame->GetProvidedParametersCount();
2997 Object* result = Heap::AllocateArgumentsObject(callee, length);
2998 if (result->IsFailure()) return result;
2999 FixedArray* array = FixedArray::cast(JSObject::cast(result)->elements());
3000 ASSERT(array->length() == length);
3001 for (int i = 0; i < length; i++) {
3002 array->set(i, frame->GetParameter(i));
3003 }
3004 return result;
3005}
3006
3007
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003008static Object* Runtime_NewArgumentsFast(Arguments args) {
3009 NoHandleAllocation ha;
3010 ASSERT(args.length() == 3);
3011
3012 JSFunction* callee = JSFunction::cast(args[0]);
3013 Object** parameters = reinterpret_cast<Object**>(args[1]);
3014 const int length = Smi::cast(args[2])->value();
3015
3016 Object* result = Heap::AllocateArgumentsObject(callee, length);
3017 if (result->IsFailure()) return result;
3018 FixedArray* array = FixedArray::cast(JSObject::cast(result)->elements());
3019 ASSERT(array->length() == length);
3020 FixedArray::WriteBarrierMode mode = array->GetWriteBarrierMode();
3021 for (int i = 0; i < length; i++) {
3022 array->set(i, *--parameters, mode);
3023 }
3024 return result;
3025}
3026
3027
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003028static Object* Runtime_NewClosure(Arguments args) {
3029 HandleScope scope;
3030 ASSERT(args.length() == 2);
3031 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
3032 CONVERT_ARG_CHECKED(Context, context, 1);
3033
3034 Handle<JSFunction> result =
3035 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3036 return *result;
3037}
3038
3039
3040static Object* Runtime_NewObject(Arguments args) {
3041 NoHandleAllocation ha;
3042 ASSERT(args.length() == 1);
3043
3044 Object* constructor = args[0];
3045 if (constructor->IsJSFunction()) {
3046 JSFunction* function = JSFunction::cast(constructor);
3047
3048 // Handle steping into constructors.
3049 if (Debug::StepInActive()) {
3050 StackFrameIterator it;
3051 it.Advance();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003052 ASSERT(it.frame()->is_construct());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053 it.Advance();
3054 if (it.frame()->fp() == Debug::step_in_fp()) {
3055 HandleScope scope;
3056 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
3057 }
3058 }
3059
3060 if (function->has_initial_map() &&
3061 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
3062 // The 'Function' function ignores the receiver object when
3063 // called using 'new' and creates a new JSFunction object that
3064 // is returned. The receiver object is only used for error
3065 // reporting if an error occurs when constructing the new
3066 // JSFunction. AllocateJSObject should not be used to allocate
3067 // JSFunctions since it does not properly initialize the shared
3068 // part of the function. Since the receiver is ignored anyway,
3069 // we use the global object as the receiver instead of a new
3070 // JSFunction object. This way, errors are reported the same
3071 // way whether or not 'Function' is called using 'new'.
3072 return Top::context()->global();
3073 }
3074 return Heap::AllocateJSObject(function);
3075 }
3076
3077 HandleScope scope;
3078 Handle<Object> cons(constructor);
3079 // The constructor is not a function; throw a type error.
3080 Handle<Object> type_error =
3081 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
3082 return Top::Throw(*type_error);
3083}
3084
3085
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086static Object* Runtime_LazyCompile(Arguments args) {
3087 HandleScope scope;
3088 ASSERT(args.length() == 1);
3089
3090 Handle<JSFunction> function = args.at<JSFunction>(0);
3091#ifdef DEBUG
3092 if (FLAG_trace_lazy) {
3093 PrintF("[lazy: ");
3094 function->shared()->name()->Print();
3095 PrintF("]\n");
3096 }
3097#endif
3098
3099 // Compile the target function.
3100 ASSERT(!function->is_compiled());
3101 if (!CompileLazy(function, KEEP_EXCEPTION)) {
3102 return Failure::Exception();
3103 }
3104
3105 return function->code();
3106}
3107
3108
3109static Object* Runtime_GetCalledFunction(Arguments args) {
3110 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00003111 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003112 StackFrameIterator it;
3113 // Get past the JS-to-C exit frame.
3114 ASSERT(it.frame()->is_exit());
3115 it.Advance();
3116 // Get past the CALL_NON_FUNCTION activation frame.
3117 ASSERT(it.frame()->is_java_script());
3118 it.Advance();
3119 // Argument adaptor frames do not copy the function; we have to skip
3120 // past them to get to the real calling frame.
3121 if (it.frame()->is_arguments_adaptor()) it.Advance();
3122 // Get the function from the top of the expression stack of the
3123 // calling frame.
3124 StandardFrame* frame = StandardFrame::cast(it.frame());
3125 int index = frame->ComputeExpressionsCount() - 1;
3126 Object* result = frame->GetExpression(index);
3127 return result;
3128}
3129
3130
3131static Object* Runtime_GetFunctionDelegate(Arguments args) {
3132 HandleScope scope;
3133 ASSERT(args.length() == 1);
3134 RUNTIME_ASSERT(!args[0]->IsJSFunction());
3135 return *Execution::GetFunctionDelegate(args.at<Object>(0));
3136}
3137
3138
3139static Object* Runtime_NewContext(Arguments args) {
3140 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003141 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003142
kasper.lund7276f142008-07-30 08:49:36 +00003143 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003144 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
3145 Object* result = Heap::AllocateFunctionContext(length, function);
3146 if (result->IsFailure()) return result;
3147
3148 Top::set_context(Context::cast(result));
3149
kasper.lund7276f142008-07-30 08:49:36 +00003150 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003151}
3152
3153
3154static Object* Runtime_PushContext(Arguments args) {
3155 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003156 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003157
3158 // Convert the object to a proper JavaScript object.
kasper.lund7276f142008-07-30 08:49:36 +00003159 Object* object = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003160 if (!object->IsJSObject()) {
3161 object = object->ToObject();
3162 if (object->IsFailure()) {
3163 if (!Failure::cast(object)->IsInternalError()) return object;
3164 HandleScope scope;
kasper.lund7276f142008-07-30 08:49:36 +00003165 Handle<Object> handle(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003166 Handle<Object> result =
3167 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
3168 return Top::Throw(*result);
3169 }
3170 }
3171
3172 Object* result =
3173 Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
3174 if (result->IsFailure()) return result;
3175
3176 Top::set_context(Context::cast(result));
3177
kasper.lund7276f142008-07-30 08:49:36 +00003178 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003179}
3180
3181
3182static Object* Runtime_LookupContext(Arguments args) {
3183 HandleScope scope;
3184 ASSERT(args.length() == 2);
3185
3186 CONVERT_ARG_CHECKED(Context, context, 0);
3187 CONVERT_ARG_CHECKED(String, name, 1);
3188
3189 int index;
3190 PropertyAttributes attributes;
3191 ContextLookupFlags flags = FOLLOW_CHAINS;
3192 Handle<Object> context_obj =
3193 context->Lookup(name, flags, &index, &attributes);
3194
3195 if (index < 0 && *context_obj != NULL) {
3196 ASSERT(context_obj->IsJSObject());
3197 return *context_obj;
3198 }
3199
3200 // No intermediate context found. Use global object by default.
3201 return Top::context()->global();
3202}
3203
3204
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003205// A mechanism to return pairs of Object*'s. This is somewhat
3206// compiler-dependent as it assumes that a 64-bit value (a long long)
3207// is returned via two registers (edx:eax on ia32). Both the ia32 and
3208// arm platform support this; it is mostly an issue of "coaxing" the
3209// compiler to do the right thing.
3210//
3211// TODO(1236026): This is a non-portable hack that should be removed.
3212typedef uint64_t ObjPair;
3213ObjPair MakePair(Object* x, Object* y) {
3214 return reinterpret_cast<uint32_t>(x) |
3215 (reinterpret_cast<ObjPair>(y) << 32);
3216}
3217
3218
3219static Object* Unhole(Object* x, PropertyAttributes attributes) {
3220 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
3221 USE(attributes);
3222 return x->IsTheHole() ? Heap::undefined_value() : x;
3223}
3224
3225
3226static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) {
3227 HandleScope scope;
3228 ASSERT(args.length() == 2);
3229
3230 if (!args[0]->IsContext()) return MakePair(IllegalOperation(), NULL);
3231 Handle<Context> context = args.at<Context>(0);
3232 Handle<String> name(String::cast(args[1]));
3233
3234 int index;
3235 PropertyAttributes attributes;
3236 ContextLookupFlags flags = FOLLOW_CHAINS;
3237 Handle<Object> context_obj =
3238 context->Lookup(name, flags, &index, &attributes);
3239
3240 if (index >= 0) {
3241 if (context_obj->IsContext()) {
3242 // The context is an Execution context, and the "property" we were looking
3243 // for is a local variable in that context. According to ECMA-262, 3rd.,
3244 // 10.1.6 and 10.2.3, the receiver is the global object.
3245 return MakePair(
3246 Unhole(Handle<Context>::cast(context_obj)->get(index), attributes),
3247 Top::context()->global());
3248 } else {
3249 return MakePair(
3250 Unhole(Handle<JSObject>::cast(context_obj)->GetElement(index),
3251 attributes),
3252 *context_obj);
3253 }
3254 }
3255
3256 if (*context_obj != NULL) {
3257 ASSERT(Handle<JSObject>::cast(context_obj)->HasProperty(*name));
3258 // Note: As of 5/29/2008, GetProperty does the "unholing" and so this call
3259 // here is redundant. We left it anyway, to be explicit; also it's not clear
3260 // why GetProperty should do the unholing in the first place.
3261 return MakePair(
3262 Unhole(Handle<JSObject>::cast(context_obj)->GetProperty(*name),
3263 attributes),
3264 *context_obj);
3265 }
3266
3267 if (throw_error) {
3268 // The property doesn't exist - throw exception.
3269 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003270 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003271 return MakePair(Top::Throw(*reference_error), NULL);
3272 } else {
3273 // The property doesn't exist - return undefined
3274 return MakePair(Heap::undefined_value(), Heap::undefined_value());
3275 }
3276}
3277
3278
3279static ObjPair Runtime_LoadContextSlot(Arguments args) {
3280 return LoadContextSlotHelper(args, true);
3281}
3282
3283
3284static ObjPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
3285 return LoadContextSlotHelper(args, false);
3286}
3287
3288
3289static Object* Runtime_StoreContextSlot(Arguments args) {
3290 HandleScope scope;
3291 ASSERT(args.length() == 3);
3292
3293 Handle<Object> value(args[0]);
3294 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003295 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296
3297 int index;
3298 PropertyAttributes attributes;
3299 ContextLookupFlags flags = FOLLOW_CHAINS;
3300 Handle<Object> context_obj =
3301 context->Lookup(name, flags, &index, &attributes);
3302
3303 if (index >= 0) {
3304 if (context_obj->IsContext()) {
3305 // Ignore if read_only variable.
3306 if ((attributes & READ_ONLY) == 0) {
3307 Handle<Context>::cast(context_obj)->set(index, *value);
3308 }
3309 } else {
3310 ASSERT((attributes & READ_ONLY) == 0);
3311 Object* result =
3312 Handle<JSObject>::cast(context_obj)->SetElement(index, *value);
3313 USE(result);
3314 ASSERT(!result->IsFailure());
3315 }
3316 return *value;
3317 }
3318
3319 // Slow case: The property is not in a FixedArray context.
3320 // It is either in an JSObject extension context or it was not found.
3321 Handle<JSObject> context_ext;
3322
3323 if (*context_obj != NULL) {
3324 // The property exists in the extension context.
3325 context_ext = Handle<JSObject>::cast(context_obj);
3326 } else {
3327 // The property was not found. It needs to be stored in the global context.
3328 ASSERT(attributes == ABSENT);
3329 attributes = NONE;
3330 context_ext = Handle<JSObject>(Top::context()->global());
3331 }
3332
3333 // Set the property, but ignore if read_only variable.
3334 if ((attributes & READ_ONLY) == 0) {
3335 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
3336 if (set.is_null()) {
3337 // Failure::Exception is converted to a null handle in the
3338 // handle-based methods such as SetProperty. We therefore need
3339 // to convert null handles back to exceptions.
3340 ASSERT(Top::has_pending_exception());
3341 return Failure::Exception();
3342 }
3343 }
3344 return *value;
3345}
3346
3347
3348static Object* Runtime_Throw(Arguments args) {
3349 HandleScope scope;
3350 ASSERT(args.length() == 1);
3351
3352 return Top::Throw(args[0]);
3353}
3354
3355
3356static Object* Runtime_ReThrow(Arguments args) {
3357 HandleScope scope;
3358 ASSERT(args.length() == 1);
3359
3360 return Top::ReThrow(args[0]);
3361}
3362
3363
3364static Object* Runtime_ThrowReferenceError(Arguments args) {
3365 HandleScope scope;
3366 ASSERT(args.length() == 1);
3367
3368 Handle<Object> name(args[0]);
3369 Handle<Object> reference_error =
3370 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3371 return Top::Throw(*reference_error);
3372}
3373
3374
3375static Object* Runtime_StackOverflow(Arguments args) {
3376 NoHandleAllocation na;
3377 return Top::StackOverflow();
3378}
3379
3380
3381static Object* RuntimePreempt(Arguments args) {
3382 // Clear the preempt request flag.
3383 StackGuard::Continue(PREEMPT);
3384
3385 ContextSwitcher::PreemptionReceived();
3386
3387 {
3388 v8::Unlocker unlocker;
3389 Thread::YieldCPU();
3390 }
3391
3392 return Heap::undefined_value();
3393}
3394
3395
3396static Object* Runtime_DebugBreak(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003397 // Just continue if breaks are disabled.
3398 if (Debug::disable_break()) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003399 return args[0];
3400 }
3401
kasper.lund7276f142008-07-30 08:49:36 +00003402 // Don't break in system functions. If the current function is
3403 // either in the builtins object of some context or is in the debug
3404 // context just return with the debug break stack guard active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 JavaScriptFrameIterator it;
3406 JavaScriptFrame* frame = it.frame();
3407 Object* fun = frame->function();
3408 if (fun->IsJSFunction()) {
3409 GlobalObject* global = JSFunction::cast(fun)->context()->global();
3410 if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
3411 return args[0];
3412 }
3413 }
3414
3415 // Clear the debug request flag.
3416 StackGuard::Continue(DEBUGBREAK);
3417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418 HandleScope scope;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003419 // Enter the debugger. Just continue if we fail to enter the debugger.
3420 EnterDebugger debugger;
3421 if (debugger.FailedToEnter()) {
3422 return args[0];
3423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424
kasper.lund7276f142008-07-30 08:49:36 +00003425 // Notify the debug event listeners.
3426 Debugger::OnDebugBreak(Factory::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003427
3428 // Return to continue execution.
3429 return args[0];
3430}
3431
3432
3433static Object* Runtime_StackGuard(Arguments args) {
3434 ASSERT(args.length() == 1);
3435
3436 // First check if this is a real stack overflow.
3437 if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
3438
3439 // If not real stack overflow the stack guard was used to interrupt
3440 // execution for another purpose.
3441 if (StackGuard::IsDebugBreak()) Runtime_DebugBreak(args);
3442 if (StackGuard::IsPreempted()) RuntimePreempt(args);
3443 if (StackGuard::IsInterrupted()) {
3444 // interrupt
3445 StackGuard::Continue(INTERRUPT);
3446 return Top::StackOverflow();
3447 }
3448 return Heap::undefined_value();
3449}
3450
3451
3452// NOTE: These PrintXXX functions are defined for all builds (not just
3453// DEBUG builds) because we may want to be able to trace function
3454// calls in all modes.
3455static void PrintString(String* str) {
3456 // not uncommon to have empty strings
3457 if (str->length() > 0) {
3458 SmartPointer<char> s =
3459 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3460 PrintF("%s", *s);
3461 }
3462}
3463
3464
3465static void PrintObject(Object* obj) {
3466 if (obj->IsSmi()) {
3467 PrintF("%d", Smi::cast(obj)->value());
3468 } else if (obj->IsString() || obj->IsSymbol()) {
3469 PrintString(String::cast(obj));
3470 } else if (obj->IsNumber()) {
3471 PrintF("%g", obj->Number());
3472 } else if (obj->IsFailure()) {
3473 PrintF("<failure>");
3474 } else if (obj->IsUndefined()) {
3475 PrintF("<undefined>");
3476 } else if (obj->IsNull()) {
3477 PrintF("<null>");
3478 } else if (obj->IsTrue()) {
3479 PrintF("<true>");
3480 } else if (obj->IsFalse()) {
3481 PrintF("<false>");
3482 } else {
3483 PrintF("%p", obj);
3484 }
3485}
3486
3487
3488static int StackSize() {
3489 int n = 0;
3490 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3491 return n;
3492}
3493
3494
3495static void PrintTransition(Object* result) {
3496 // indentation
3497 { const int nmax = 80;
3498 int n = StackSize();
3499 if (n <= nmax)
3500 PrintF("%4d:%*s", n, n, "");
3501 else
3502 PrintF("%4d:%*s", n, nmax, "...");
3503 }
3504
3505 if (result == NULL) {
3506 // constructor calls
3507 JavaScriptFrameIterator it;
3508 JavaScriptFrame* frame = it.frame();
3509 if (frame->IsConstructor()) PrintF("new ");
3510 // function name
3511 Object* fun = frame->function();
3512 if (fun->IsJSFunction()) {
3513 PrintObject(JSFunction::cast(fun)->shared()->name());
3514 } else {
3515 PrintObject(fun);
3516 }
3517 // function arguments
3518 // (we are intentionally only printing the actually
3519 // supplied parameters, not all parameters required)
3520 PrintF("(this=");
3521 PrintObject(frame->receiver());
3522 const int length = frame->GetProvidedParametersCount();
3523 for (int i = 0; i < length; i++) {
3524 PrintF(", ");
3525 PrintObject(frame->GetParameter(i));
3526 }
3527 PrintF(") {\n");
3528
3529 } else {
3530 // function result
3531 PrintF("} -> ");
3532 PrintObject(result);
3533 PrintF("\n");
3534 }
3535}
3536
3537
3538static Object* Runtime_TraceEnter(Arguments args) {
3539 NoHandleAllocation ha;
3540 PrintTransition(NULL);
3541 return args[0]; // return TOS
3542}
3543
3544
3545static Object* Runtime_TraceExit(Arguments args) {
3546 NoHandleAllocation ha;
3547 PrintTransition(args[0]);
3548 return args[0]; // return TOS
3549}
3550
3551
3552static Object* Runtime_DebugPrint(Arguments args) {
3553 NoHandleAllocation ha;
3554 ASSERT(args.length() == 1);
3555
3556#ifdef DEBUG
3557 if (args[0]->IsString()) {
3558 // If we have a string, assume it's a code "marker"
3559 // and print some interesting cpu debugging info.
3560 JavaScriptFrameIterator it;
3561 JavaScriptFrame* frame = it.frame();
3562 PrintF("fp = %p, sp = %p, pp = %p: ",
3563 frame->fp(), frame->sp(), frame->pp());
3564 } else {
3565 PrintF("DebugPrint: ");
3566 }
3567 args[0]->Print();
3568#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003569 // ShortPrint is available in release mode. Print is not.
3570 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571#endif
3572 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00003573 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003574
3575 return args[0]; // return TOS
3576}
3577
3578
3579static Object* Runtime_DebugTrace(Arguments args) {
3580 ASSERT(args.length() == 1);
3581 NoHandleAllocation ha;
3582 Top::PrintStack();
3583 return args[0]; // return TOS
3584}
3585
3586
mads.s.ager31e71382008-08-13 09:32:07 +00003587static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003588 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003589 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590
3591 // According to ECMA-262, section 15.9.1, page 117, the precision of
3592 // the number in a Date object representing a particular instant in
3593 // time is milliseconds. Therefore, we floor the result of getting
3594 // the OS time.
3595 double millis = floor(OS::TimeCurrentMillis());
3596 return Heap::NumberFromDouble(millis);
3597}
3598
3599
3600static Object* Runtime_DateParseString(Arguments args) {
3601 HandleScope scope;
3602 ASSERT(args.length() == 1);
3603
3604 CONVERT_CHECKED(String, string_object, args[0]);
3605
3606 Handle<String> str(string_object);
3607 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3608 if (DateParser::Parse(*str, *output)) {
3609 return *Factory::NewJSArrayWithElements(output);
3610 } else {
3611 return *Factory::null_value();
3612 }
3613}
3614
3615
3616static Object* Runtime_DateLocalTimezone(Arguments args) {
3617 NoHandleAllocation ha;
3618 ASSERT(args.length() == 1);
3619
3620 CONVERT_DOUBLE_CHECKED(x, args[0]);
3621 char* zone = OS::LocalTimezone(x);
3622 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3623}
3624
3625
3626static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3627 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003628 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629
3630 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3631}
3632
3633
3634static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3635 NoHandleAllocation ha;
3636 ASSERT(args.length() == 1);
3637
3638 CONVERT_DOUBLE_CHECKED(x, args[0]);
3639 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3640}
3641
3642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643static Object* Runtime_NumberIsFinite(Arguments args) {
3644 NoHandleAllocation ha;
3645 ASSERT(args.length() == 1);
3646
3647 CONVERT_DOUBLE_CHECKED(value, args[0]);
3648 Object* result;
3649 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3650 result = Heap::false_value();
3651 } else {
3652 result = Heap::true_value();
3653 }
3654 return result;
3655}
3656
3657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658static Object* EvalContext() {
3659 // The topmost JS frame belongs to the eval function which called
3660 // the CompileString runtime function. We need to unwind one level
3661 // to get to the caller of eval.
3662 StackFrameLocator locator;
3663 JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
3664
kasper.lund44510672008-07-25 07:37:58 +00003665 // TODO(900055): Right now we check if the caller of eval() supports
3666 // eval to determine if it's an aliased eval or not. This may not be
3667 // entirely correct in the unlikely case where a function uses both
3668 // aliased and direct eval calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669 HandleScope scope;
3670 if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
kasper.lund44510672008-07-25 07:37:58 +00003671 // Aliased eval: Evaluate in the global context of the eval
3672 // function to support aliased, cross environment evals.
3673 return *Top::global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674 }
3675
3676 // Fetch the caller context from the frame.
3677 Handle<Context> caller(Context::cast(frame->context()));
3678
3679 // Check for eval() invocations that cross environments. Use the
3680 // context from the stack if evaluating in current environment.
3681 Handle<Context> target = Top::global_context();
3682 if (caller->global_context() == *target) return *caller;
3683
3684 // Compute a function closure that captures the calling context. We
3685 // need a function that has trivial scope info, since it is only
3686 // used to hold the context chain together.
3687 Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
3688 Factory::undefined_value());
3689 closure->set_context(*caller);
3690
3691 // Create a new adaptor context that has the target environment as
3692 // the extension object. This enables the evaluated code to see both
3693 // the current context with locals and everything and to see global
3694 // variables declared in the target global object. Furthermore, any
3695 // properties introduced with 'var' will be added to the target
3696 // global object because it is the extension object.
3697 Handle<Context> adaptor =
3698 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
3699 adaptor->set_extension(target->global());
3700 return *adaptor;
3701}
3702
3703
3704static Object* Runtime_EvalReceiver(Arguments args) {
3705 StackFrameLocator locator;
3706 return locator.FindJavaScriptFrame(1)->receiver();
3707}
3708
3709
3710static Object* Runtime_CompileString(Arguments args) {
3711 HandleScope scope;
ager@chromium.org236ad962008-09-25 09:45:57 +00003712 ASSERT(args.length() == 3);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003713 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org236ad962008-09-25 09:45:57 +00003714 CONVERT_ARG_CHECKED(Smi, line_offset, 1);
3715 bool contextual = args[2]->IsTrue();
3716 RUNTIME_ASSERT(contextual || args[2]->IsFalse());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003717
3718 // Compute the eval context.
3719 Handle<Context> context;
3720 if (contextual) {
3721 // Get eval context. May not be available if we are calling eval
3722 // through an alias, and the corresponding frame doesn't have a
3723 // proper eval context set up.
3724 Object* eval_context = EvalContext();
3725 if (eval_context->IsFailure()) return eval_context;
3726 context = Handle<Context>(Context::cast(eval_context));
3727 } else {
3728 context = Handle<Context>(Top::context()->global_context());
3729 }
3730
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003731
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003732 // Compile source string.
3733 bool is_global = context->IsGlobalContext();
3734 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00003735 Compiler::CompileEval(source, line_offset->value(), is_global);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003736 if (boilerplate.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737 Handle<JSFunction> fun =
3738 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3739 return *fun;
3740}
3741
3742
3743static Object* Runtime_CompileScript(Arguments args) {
3744 HandleScope scope;
3745 ASSERT(args.length() == 4);
3746
3747 CONVERT_ARG_CHECKED(String, source, 0);
3748 CONVERT_ARG_CHECKED(String, script, 1);
3749 CONVERT_CHECKED(Smi, line_attrs, args[2]);
3750 int line = line_attrs->value();
3751 CONVERT_CHECKED(Smi, col_attrs, args[3]);
3752 int col = col_attrs->value();
3753 Handle<JSFunction> boilerplate =
3754 Compiler::Compile(source, script, line, col, NULL, NULL);
3755 if (boilerplate.is_null()) return Failure::Exception();
3756 Handle<JSFunction> fun =
3757 Factory::NewFunctionFromBoilerplate(boilerplate,
3758 Handle<Context>(Top::context()));
3759 return *fun;
3760}
3761
3762
3763static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
3764 // This utility adjusts the property attributes for newly created Function
3765 // object ("new Function(...)") by changing the map.
3766 // All it does is changing the prototype property to enumerable
3767 // as specified in ECMA262, 15.3.5.2.
3768 HandleScope scope;
3769 ASSERT(args.length() == 1);
3770 CONVERT_ARG_CHECKED(JSFunction, func, 0);
3771 ASSERT(func->map()->instance_type() ==
3772 Top::function_instance_map()->instance_type());
3773 ASSERT(func->map()->instance_size() ==
3774 Top::function_instance_map()->instance_size());
3775 func->set_map(*Top::function_instance_map());
3776 return *func;
3777}
3778
3779
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003780// Push an array unto an array of arrays if it is not already in the
3781// array. Returns true if the element was pushed on the stack and
3782// false otherwise.
3783static Object* Runtime_PushIfAbsent(Arguments args) {
3784 ASSERT(args.length() == 2);
3785 CONVERT_CHECKED(JSArray, array, args[0]);
3786 CONVERT_CHECKED(JSArray, element, args[1]);
3787 RUNTIME_ASSERT(array->HasFastElements());
3788 int length = Smi::cast(array->length())->value();
3789 FixedArray* elements = FixedArray::cast(array->elements());
3790 for (int i = 0; i < length; i++) {
3791 if (elements->get(i) == element) return Heap::false_value();
3792 }
3793 Object* obj = array->SetFastElement(length, element);
3794 if (obj->IsFailure()) return obj;
3795 return Heap::true_value();
3796}
3797
3798
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003799// This will not allocate (flatten the string), but it may run
3800// very slowly for very deeply nested ConsStrings. For debugging use only.
3801static Object* Runtime_GlobalPrint(Arguments args) {
3802 NoHandleAllocation ha;
3803 ASSERT(args.length() == 1);
3804
3805 CONVERT_CHECKED(String, string, args[0]);
3806 StringInputBuffer buffer(string);
3807 while (buffer.has_more()) {
3808 uint16_t character = buffer.GetNext();
3809 PrintF("%c", character);
3810 }
3811 return string;
3812}
3813
3814
3815static Object* Runtime_RemoveArrayHoles(Arguments args) {
3816 ASSERT(args.length() == 1);
3817 // Ignore the case if this is not a JSArray.
3818 if (!args[0]->IsJSArray()) return args[0];
3819 return JSArray::cast(args[0])->RemoveHoles();
3820}
3821
3822
3823// Move contents of argument 0 (an array) to argument 1 (an array)
3824static Object* Runtime_MoveArrayContents(Arguments args) {
3825 ASSERT(args.length() == 2);
3826 CONVERT_CHECKED(JSArray, from, args[0]);
3827 CONVERT_CHECKED(JSArray, to, args[1]);
3828 to->SetContent(FixedArray::cast(from->elements()));
3829 to->set_length(from->length());
3830 from->SetContent(Heap::empty_fixed_array());
3831 from->set_length(0);
3832 return to;
3833}
3834
3835
3836// How many elements does this array have?
3837static Object* Runtime_EstimateNumberOfElements(Arguments args) {
3838 ASSERT(args.length() == 1);
3839 CONVERT_CHECKED(JSArray, array, args[0]);
3840 HeapObject* elements = array->elements();
3841 if (elements->IsDictionary()) {
3842 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
3843 } else {
3844 return array->length();
3845 }
3846}
3847
3848
3849// Returns an array that tells you where in the [0, length) interval an array
3850// might have elements. Can either return keys or intervals. Keys can have
3851// gaps in (undefined). Intervals can also span over some undefined keys.
3852static Object* Runtime_GetArrayKeys(Arguments args) {
3853 ASSERT(args.length() == 2);
3854 HandleScope scope;
3855 CONVERT_CHECKED(JSArray, raw_array, args[0]);
3856 Handle<JSArray> array(raw_array);
3857 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003858 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003859 // Create an array and get all the keys into it, then remove all the
3860 // keys that are not integers in the range 0 to length-1.
3861 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
3862 int keys_length = keys->length();
3863 for (int i = 0; i < keys_length; i++) {
3864 Object* key = keys->get(i);
3865 uint32_t index;
3866 if (!Array::IndexFromObject(key, &index) || index >= length) {
3867 // Zap invalid keys.
3868 keys->set_undefined(i);
3869 }
3870 }
3871 return *Factory::NewJSArrayWithElements(keys);
3872 } else {
3873 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
3874 // -1 means start of array.
3875 single_interval->set(0, Smi::FromInt(-1));
3876 Handle<Object> length_object =
3877 Factory::NewNumber(static_cast<double>(length));
3878 single_interval->set(1, *length_object);
3879 return *Factory::NewJSArrayWithElements(single_interval);
3880 }
3881}
3882
3883
3884// DefineAccessor takes an optional final argument which is the
3885// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
3886// to the way accessors are implemented, it is set for both the getter
3887// and setter on the first call to DefineAccessor and ignored on
3888// subsequent calls.
3889static Object* Runtime_DefineAccessor(Arguments args) {
3890 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
3891 // Compute attributes.
3892 PropertyAttributes attributes = NONE;
3893 if (args.length() == 5) {
3894 CONVERT_CHECKED(Smi, attrs, args[4]);
3895 int value = attrs->value();
3896 // Only attribute bits should be set.
3897 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3898 attributes = static_cast<PropertyAttributes>(value);
3899 }
3900
3901 CONVERT_CHECKED(JSObject, obj, args[0]);
3902 CONVERT_CHECKED(String, name, args[1]);
3903 CONVERT_CHECKED(Smi, flag, args[2]);
3904 CONVERT_CHECKED(JSFunction, fun, args[3]);
3905 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
3906}
3907
3908
3909static Object* Runtime_LookupAccessor(Arguments args) {
3910 ASSERT(args.length() == 3);
3911 CONVERT_CHECKED(JSObject, obj, args[0]);
3912 CONVERT_CHECKED(String, name, args[1]);
3913 CONVERT_CHECKED(Smi, flag, args[2]);
3914 return obj->LookupAccessor(name, flag->value() == 0);
3915}
3916
3917
3918// Helper functions for wrapping and unwrapping stack frame ids.
3919static Smi* WrapFrameId(StackFrame::Id id) {
3920 ASSERT(IsAligned(OffsetFrom(id), 4));
3921 return Smi::FromInt(id >> 2);
3922}
3923
3924
3925static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
3926 return static_cast<StackFrame::Id>(wrapped->value() << 2);
3927}
3928
3929
3930// Adds a JavaScript function as a debug event listener.
3931// args[0]: debug event listener function
3932// args[1]: object supplied during callback
3933static Object* Runtime_AddDebugEventListener(Arguments args) {
3934 ASSERT(args.length() == 2);
3935 // Convert the parameters to API objects to call the API function for adding
3936 // a JavaScript function as debug event listener.
3937 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
3938 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
3939 v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
3940 v8::Debug::AddDebugEventListener(fun, data);
3941
3942 return Heap::undefined_value();
3943}
3944
3945
3946// Removes a JavaScript function debug event listener.
3947// args[0]: debug event listener function
3948static Object* Runtime_RemoveDebugEventListener(Arguments args) {
3949 ASSERT(args.length() == 1);
3950 // Convert the parameter to an API object to call the API function for
3951 // removing a JavaScript function debug event listener.
3952 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
3953 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
3954 v8::Debug::RemoveDebugEventListener(fun);
3955
3956 return Heap::undefined_value();
3957}
3958
3959
3960static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00003961 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 StackGuard::DebugBreak();
3963 return Heap::undefined_value();
3964}
3965
3966
3967static Object* DebugLookupResultValue(LookupResult* result) {
3968 Object* value;
3969 switch (result->type()) {
3970 case NORMAL: {
3971 Dictionary* dict =
3972 JSObject::cast(result->holder())->property_dictionary();
3973 value = dict->ValueAt(result->GetDictionaryEntry());
3974 if (value->IsTheHole()) {
3975 return Heap::undefined_value();
3976 }
3977 return value;
3978 }
3979 case FIELD:
3980 value =
3981 JSObject::cast(
ager@chromium.org7c537e22008-10-16 08:43:32 +00003982 result->holder())->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 if (value->IsTheHole()) {
3984 return Heap::undefined_value();
3985 }
3986 return value;
3987 case CONSTANT_FUNCTION:
3988 return result->GetConstantFunction();
3989 case CALLBACKS:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003991 case MAP_TRANSITION:
3992 case CONSTANT_TRANSITION:
3993 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 return Heap::undefined_value();
3995 default:
3996 UNREACHABLE();
3997 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003998 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 return Heap::undefined_value();
4000}
4001
4002
4003static Object* Runtime_DebugGetLocalPropertyDetails(Arguments args) {
4004 HandleScope scope;
4005
4006 ASSERT(args.length() == 2);
4007
4008 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4009 CONVERT_ARG_CHECKED(String, name, 1);
4010
4011 // Check if the name is trivially convertible to an index and get the element
4012 // if so.
4013 uint32_t index;
4014 if (name->AsArrayIndex(&index)) {
4015 Handle<FixedArray> details = Factory::NewFixedArray(2);
4016 details->set(0, Runtime::GetElementOrCharAt(obj, index));
4017 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
4018 return *Factory::NewJSArrayWithElements(details);
4019 }
4020
4021 // Perform standard local lookup on the object.
4022 LookupResult result;
4023 obj->LocalLookup(*name, &result);
4024 if (result.IsProperty()) {
4025 Handle<Object> value(DebugLookupResultValue(&result));
4026 Handle<FixedArray> details = Factory::NewFixedArray(2);
4027 details->set(0, *value);
4028 details->set(1, result.GetPropertyDetails().AsSmi());
4029 return *Factory::NewJSArrayWithElements(details);
4030 }
4031 return Heap::undefined_value();
4032}
4033
4034
4035static Object* Runtime_DebugGetProperty(Arguments args) {
4036 HandleScope scope;
4037
4038 ASSERT(args.length() == 2);
4039
4040 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4041 CONVERT_ARG_CHECKED(String, name, 1);
4042
4043 LookupResult result;
4044 obj->Lookup(*name, &result);
4045 if (result.IsProperty()) {
4046 return DebugLookupResultValue(&result);
4047 }
4048 return Heap::undefined_value();
4049}
4050
4051
4052// Return the names of the local named properties.
4053// args[0]: object
4054static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
4055 HandleScope scope;
4056 ASSERT(args.length() == 1);
4057 if (!args[0]->IsJSObject()) {
4058 return Heap::undefined_value();
4059 }
4060 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4061
4062 int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4063 Handle<FixedArray> names = Factory::NewFixedArray(n);
4064 obj->GetLocalPropertyNames(*names);
4065 return *Factory::NewJSArrayWithElements(names);
4066}
4067
4068
4069// Return the names of the local indexed properties.
4070// args[0]: object
4071static Object* Runtime_DebugLocalElementNames(Arguments args) {
4072 HandleScope scope;
4073 ASSERT(args.length() == 1);
4074 if (!args[0]->IsJSObject()) {
4075 return Heap::undefined_value();
4076 }
4077 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4078
4079 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4080 Handle<FixedArray> names = Factory::NewFixedArray(n);
4081 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4082 return *Factory::NewJSArrayWithElements(names);
4083}
4084
4085
4086// Return the property type calculated from the property details.
4087// args[0]: smi with property details.
4088static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
4089 ASSERT(args.length() == 1);
4090 CONVERT_CHECKED(Smi, details, args[0]);
4091 PropertyType type = PropertyDetails(details).type();
4092 return Smi::FromInt(static_cast<int>(type));
4093}
4094
4095
4096// Return the property attribute calculated from the property details.
4097// args[0]: smi with property details.
4098static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
4099 ASSERT(args.length() == 1);
4100 CONVERT_CHECKED(Smi, details, args[0]);
4101 PropertyAttributes attributes = PropertyDetails(details).attributes();
4102 return Smi::FromInt(static_cast<int>(attributes));
4103}
4104
4105
4106// Return the property insertion index calculated from the property details.
4107// args[0]: smi with property details.
4108static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
4109 ASSERT(args.length() == 1);
4110 CONVERT_CHECKED(Smi, details, args[0]);
4111 int index = PropertyDetails(details).index();
4112 return Smi::FromInt(index);
4113}
4114
4115
4116// Return information on whether an object has a named or indexed interceptor.
4117// args[0]: object
4118static Object* Runtime_DebugInterceptorInfo(Arguments args) {
4119 HandleScope scope;
4120 ASSERT(args.length() == 1);
4121 if (!args[0]->IsJSObject()) {
4122 return Smi::FromInt(0);
4123 }
4124 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4125
4126 int result = 0;
4127 if (obj->HasNamedInterceptor()) result |= 2;
4128 if (obj->HasIndexedInterceptor()) result |= 1;
4129
4130 return Smi::FromInt(result);
4131}
4132
4133
4134// Return property names from named interceptor.
4135// args[0]: object
4136static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
4137 HandleScope scope;
4138 ASSERT(args.length() == 1);
4139 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4140 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4141
4142 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4143 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4144 return Heap::undefined_value();
4145}
4146
4147
4148// Return element names from indexed interceptor.
4149// args[0]: object
4150static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
4151 HandleScope scope;
4152 ASSERT(args.length() == 1);
4153 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4154 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4155
4156 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4157 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4158 return Heap::undefined_value();
4159}
4160
4161
4162// Return property value from named interceptor.
4163// args[0]: object
4164// args[1]: property name
4165static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
4166 HandleScope scope;
4167 ASSERT(args.length() == 2);
4168 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4169 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4170 CONVERT_ARG_CHECKED(String, name, 1);
4171
4172 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004173 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004174}
4175
4176
4177// Return element value from indexed interceptor.
4178// args[0]: object
4179// args[1]: index
4180static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
4181 HandleScope scope;
4182 ASSERT(args.length() == 2);
4183 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4184 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4185 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
4186
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004187 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188}
4189
4190
4191static Object* Runtime_CheckExecutionState(Arguments args) {
4192 ASSERT(args.length() >= 1);
4193 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
4194 // Check that the break id is valid and that there is a valid frame
4195 // where execution is broken.
4196 if (break_id != Top::break_id() ||
4197 Top::break_frame_id() == StackFrame::NO_ID) {
4198 return Top::Throw(Heap::illegal_execution_state_symbol());
4199 }
4200
4201 return Heap::true_value();
4202}
4203
4204
4205static Object* Runtime_GetFrameCount(Arguments args) {
4206 HandleScope scope;
4207 ASSERT(args.length() == 1);
4208
4209 // Check arguments.
4210 Object* result = Runtime_CheckExecutionState(args);
4211 if (result->IsFailure()) return result;
4212
4213 // Count all frames which are relevant to debugging stack trace.
4214 int n = 0;
4215 StackFrame::Id id = Top::break_frame_id();
4216 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
4217 return Smi::FromInt(n);
4218}
4219
4220
4221static const int kFrameDetailsFrameIdIndex = 0;
4222static const int kFrameDetailsReceiverIndex = 1;
4223static const int kFrameDetailsFunctionIndex = 2;
4224static const int kFrameDetailsArgumentCountIndex = 3;
4225static const int kFrameDetailsLocalCountIndex = 4;
4226static const int kFrameDetailsSourcePositionIndex = 5;
4227static const int kFrameDetailsConstructCallIndex = 6;
4228static const int kFrameDetailsDebuggerFrameIndex = 7;
4229static const int kFrameDetailsFirstDynamicIndex = 8;
4230
4231// Return an array with frame details
4232// args[0]: number: break id
4233// args[1]: number: frame index
4234//
4235// The array returned contains the following information:
4236// 0: Frame id
4237// 1: Receiver
4238// 2: Function
4239// 3: Argument count
4240// 4: Local count
4241// 5: Source position
4242// 6: Constructor call
4243// 7: Debugger frame
4244// Arguments name, value
4245// Locals name, value
4246static Object* Runtime_GetFrameDetails(Arguments args) {
4247 HandleScope scope;
4248 ASSERT(args.length() == 2);
4249
4250 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004251 Object* check = Runtime_CheckExecutionState(args);
4252 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
4254
4255 // Find the relevant frame with the requested index.
4256 StackFrame::Id id = Top::break_frame_id();
4257 int count = 0;
4258 JavaScriptFrameIterator it(id);
4259 for (; !it.done(); it.Advance()) {
4260 if (count == index) break;
4261 count++;
4262 }
4263 if (it.done()) return Heap::undefined_value();
4264
4265 // Traverse the saved contexts chain to find the active context for the
4266 // selected frame.
4267 SaveContext* save = Top::save_context();
4268 while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
4269 save = save->prev();
4270 }
4271
4272 // Get the frame id.
4273 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
4274
4275 // Find source position.
4276 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
4277
4278 // Check for constructor frame.
4279 bool constructor = it.frame()->IsConstructor();
4280
4281 // Get code and read scope info from it for local variable information.
4282 Handle<Code> code(it.frame()->FindCode());
4283 ScopeInfo<> info(*code);
4284
4285 // Get the context.
4286 Handle<Context> context(Context::cast(it.frame()->context()));
4287
4288 // Get the locals names and values into a temporary array.
4289 //
4290 // TODO(1240907): Hide compiler-introduced stack variables
4291 // (e.g. .result)? For users of the debugger, they will probably be
4292 // confusing.
4293 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
4294 for (int i = 0; i < info.NumberOfLocals(); i++) {
4295 // Name of the local.
4296 locals->set(i * 2, *info.LocalName(i));
4297
4298 // Fetch the value of the local - either from the stack or from a
4299 // heap-allocated context.
4300 if (i < info.number_of_stack_slots()) {
4301 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
4302 } else {
4303 Handle<String> name = info.LocalName(i);
4304 // Traverse the context chain to the function context as all local
4305 // variables stored in the context will be on the function context.
4306 while (context->previous() != NULL) {
4307 context = Handle<Context>(context->previous());
4308 }
4309 ASSERT(context->is_function_context());
4310 locals->set(i * 2 + 1,
4311 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
4312 NULL)));
4313 }
4314 }
4315
4316 // Now advance to the arguments adapter frame (if any). If contains all
4317 // the provided parameters and
4318
4319 // Now advance to the arguments adapter frame (if any). It contains all
4320 // the provided parameters whereas the function frame always have the number
4321 // of arguments matching the functions parameters. The rest of the
4322 // information (except for what is collected above) is the same.
4323 it.AdvanceToArgumentsFrame();
4324
4325 // Find the number of arguments to fill. At least fill the number of
4326 // parameters for the function and fill more if more parameters are provided.
4327 int argument_count = info.number_of_parameters();
4328 if (argument_count < it.frame()->GetProvidedParametersCount()) {
4329 argument_count = it.frame()->GetProvidedParametersCount();
4330 }
4331
4332 // Calculate the size of the result.
4333 int details_size = kFrameDetailsFirstDynamicIndex +
4334 2 * (argument_count + info.NumberOfLocals());
4335 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
4336
4337 // Add the frame id.
4338 details->set(kFrameDetailsFrameIdIndex, *frame_id);
4339
4340 // Add the function (same as in function frame).
4341 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
4342
4343 // Add the arguments count.
4344 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
4345
4346 // Add the locals count
4347 details->set(kFrameDetailsLocalCountIndex,
4348 Smi::FromInt(info.NumberOfLocals()));
4349
4350 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00004351 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004352 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
4353 } else {
4354 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
4355 }
4356
4357 // Add the constructor information.
4358 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
4359
4360 // Add information on whether this frame is invoked in the debugger context.
4361 details->set(kFrameDetailsDebuggerFrameIndex,
4362 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
4363
4364 // Fill the dynamic part.
4365 int details_index = kFrameDetailsFirstDynamicIndex;
4366
4367 // Add arguments name and value.
4368 for (int i = 0; i < argument_count; i++) {
4369 // Name of the argument.
4370 if (i < info.number_of_parameters()) {
4371 details->set(details_index++, *info.parameter_name(i));
4372 } else {
4373 details->set(details_index++, Heap::undefined_value());
4374 }
4375
4376 // Parameter value.
4377 if (i < it.frame()->GetProvidedParametersCount()) {
4378 details->set(details_index++, it.frame()->GetParameter(i));
4379 } else {
4380 details->set(details_index++, Heap::undefined_value());
4381 }
4382 }
4383
4384 // Add locals name and value from the temporary copy from the function frame.
4385 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
4386 details->set(details_index++, locals->get(i));
4387 }
4388
4389 // Add the receiver (same as in function frame).
4390 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
4391 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
4392 Handle<Object> receiver(it.frame()->receiver());
4393 if (!receiver->IsJSObject()) {
4394 // If the receiver is NOT a JSObject we have hit an optimization
4395 // where a value object is not converted into a wrapped JS objects.
4396 // To hide this optimization from the debugger, we wrap the receiver
4397 // by creating correct wrapper object based on the calling frame's
4398 // global context.
4399 it.Advance();
4400 Handle<Context> calling_frames_global_context(
4401 Context::cast(Context::cast(it.frame()->context())->global_context()));
4402 receiver = Factory::ToObject(receiver, calling_frames_global_context);
4403 }
4404 details->set(kFrameDetailsReceiverIndex, *receiver);
4405
4406 ASSERT_EQ(details_size, details_index);
4407 return *Factory::NewJSArrayWithElements(details);
4408}
4409
4410
4411static Object* Runtime_GetCFrames(Arguments args) {
4412 HandleScope scope;
4413 ASSERT(args.length() == 1);
4414 Object* result = Runtime_CheckExecutionState(args);
4415 if (result->IsFailure()) return result;
4416
4417 static const int kMaxCFramesSize = 200;
4418 OS::StackFrame frames[kMaxCFramesSize];
4419 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
4420 if (frames_count == OS::kStackWalkError) {
4421 return Heap::undefined_value();
4422 }
4423
4424 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
4425 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
4426 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
4427 for (int i = 0; i < frames_count; i++) {
4428 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
4429 frame_value->SetProperty(
4430 *address_str,
4431 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
4432 NONE);
4433
4434 // Get the stack walk text for this frame.
4435 Handle<String> frame_text;
4436 if (strlen(frames[i].text) > 0) {
4437 Vector<const char> str(frames[i].text, strlen(frames[i].text));
4438 frame_text = Factory::NewStringFromAscii(str);
4439 }
4440
4441 if (!frame_text.is_null()) {
4442 frame_value->SetProperty(*text_str, *frame_text, NONE);
4443 }
4444
4445 frames_array->set(i, *frame_value);
4446 }
4447 return *Factory::NewJSArrayWithElements(frames_array);
4448}
4449
4450
4451static Object* Runtime_GetBreakLocations(Arguments args) {
4452 HandleScope scope;
4453 ASSERT(args.length() == 1);
4454
4455 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4456 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4457 // Find the number of break points
4458 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
4459 if (break_locations->IsUndefined()) return Heap::undefined_value();
4460 // Return array as JS array
4461 return *Factory::NewJSArrayWithElements(
4462 Handle<FixedArray>::cast(break_locations));
4463}
4464
4465
4466// Set a break point in a function
4467// args[0]: function
4468// args[1]: number: break source position (within the function source)
4469// args[2]: number: break point object
4470static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
4471 HandleScope scope;
4472 ASSERT(args.length() == 3);
4473 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4474 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4475 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4476 RUNTIME_ASSERT(source_position >= 0);
4477 Handle<Object> break_point_object_arg = args.at<Object>(2);
4478
4479 // Set break point.
4480 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
4481
4482 return Heap::undefined_value();
4483}
4484
4485
4486static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
4487 int position) {
4488 // Iterate the heap looking for SharedFunctionInfo generated from the
4489 // script. The inner most SharedFunctionInfo containing the source position
4490 // for the requested break point is found.
4491 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
4492 // which is found is not compiled it is compiled and the heap is iterated
4493 // again as the compilation might create inner functions from the newly
4494 // compiled function and the actual requested break point might be in one of
4495 // these functions.
4496 bool done = false;
4497 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00004498 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 Handle<SharedFunctionInfo> target;
4500 // The current candidate for the last function in script:
4501 Handle<SharedFunctionInfo> last;
4502 while (!done) {
4503 HeapIterator iterator;
4504 while (iterator.has_next()) {
4505 HeapObject* obj = iterator.next();
4506 ASSERT(obj != NULL);
4507 if (obj->IsSharedFunctionInfo()) {
4508 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
4509 if (shared->script() == *script) {
4510 // If the SharedFunctionInfo found has the requested script data and
4511 // contains the source position it is a candidate.
4512 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00004513 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004514 start_position = shared->start_position();
4515 }
4516 if (start_position <= position &&
4517 position <= shared->end_position()) {
4518 // If there is no candidate or this function is within the currrent
4519 // candidate this is the new candidate.
4520 if (target.is_null()) {
4521 target_start_position = start_position;
4522 target = shared;
4523 } else {
4524 if (target_start_position < start_position &&
4525 shared->end_position() < target->end_position()) {
4526 target_start_position = start_position;
4527 target = shared;
4528 }
4529 }
4530 }
4531
4532 // Keep track of the last function in the script.
4533 if (last.is_null() ||
4534 shared->end_position() > last->start_position()) {
4535 last = shared;
4536 }
4537 }
4538 }
4539 }
4540
4541 // Make sure some candidate is selected.
4542 if (target.is_null()) {
4543 if (!last.is_null()) {
4544 // Position after the last function - use last.
4545 target = last;
4546 } else {
4547 // Unable to find function - possibly script without any function.
4548 return Heap::undefined_value();
4549 }
4550 }
4551
4552 // If the candidate found is compiled we are done. NOTE: when lazy
4553 // compilation of inner functions is introduced some additional checking
4554 // needs to be done here to compile inner functions.
4555 done = target->is_compiled();
4556 if (!done) {
4557 // If the candidate is not compiled compile it to reveal any inner
4558 // functions which might contain the requested source position.
4559 CompileLazyShared(target, KEEP_EXCEPTION);
4560 }
4561 }
4562
4563 return *target;
4564}
4565
4566
4567// Change the state of a break point in a script. NOTE: Regarding performance
4568// see the NOTE for GetScriptFromScriptData.
4569// args[0]: script to set break point in
4570// args[1]: number: break source position (within the script source)
4571// args[2]: number: break point object
4572static Object* Runtime_SetScriptBreakPoint(Arguments args) {
4573 HandleScope scope;
4574 ASSERT(args.length() == 3);
4575 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
4576 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4577 RUNTIME_ASSERT(source_position >= 0);
4578 Handle<Object> break_point_object_arg = args.at<Object>(2);
4579
4580 // Get the script from the script wrapper.
4581 RUNTIME_ASSERT(wrapper->value()->IsScript());
4582 Handle<Script> script(Script::cast(wrapper->value()));
4583
4584 Object* result = FindSharedFunctionInfoInScript(script, source_position);
4585 if (!result->IsUndefined()) {
4586 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
4587 // Find position within function. The script position might be before the
4588 // source position of the first function.
4589 int position;
4590 if (shared->start_position() > source_position) {
4591 position = 0;
4592 } else {
4593 position = source_position - shared->start_position();
4594 }
4595 Debug::SetBreakPoint(shared, position, break_point_object_arg);
4596 }
4597 return Heap::undefined_value();
4598}
4599
4600
4601// Clear a break point
4602// args[0]: number: break point object
4603static Object* Runtime_ClearBreakPoint(Arguments args) {
4604 HandleScope scope;
4605 ASSERT(args.length() == 1);
4606 Handle<Object> break_point_object_arg = args.at<Object>(0);
4607
4608 // Clear break point.
4609 Debug::ClearBreakPoint(break_point_object_arg);
4610
4611 return Heap::undefined_value();
4612}
4613
4614
4615// Change the state of break on exceptions
4616// args[0]: boolean indicating uncaught exceptions
4617// args[1]: boolean indicating on/off
4618static Object* Runtime_ChangeBreakOnException(Arguments args) {
4619 HandleScope scope;
4620 ASSERT(args.length() == 2);
4621 ASSERT(args[0]->IsNumber());
4622 ASSERT(args[1]->IsBoolean());
4623
4624 // Update break point state
4625 ExceptionBreakType type =
4626 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
4627 bool enable = args[1]->ToBoolean()->IsTrue();
4628 Debug::ChangeBreakOnException(type, enable);
4629 return Heap::undefined_value();
4630}
4631
4632
4633// Prepare for stepping
4634// args[0]: break id for checking execution state
4635// args[1]: step action from the enumeration StepAction
4636// args[2]: number of times to perform the step
4637static Object* Runtime_PrepareStep(Arguments args) {
4638 HandleScope scope;
4639 ASSERT(args.length() == 3);
4640 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004641 Object* check = Runtime_CheckExecutionState(args);
4642 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
4644 return Top::Throw(Heap::illegal_argument_symbol());
4645 }
4646
4647 // Get the step action and check validity.
4648 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
4649 if (step_action != StepIn &&
4650 step_action != StepNext &&
4651 step_action != StepOut &&
4652 step_action != StepInMin &&
4653 step_action != StepMin) {
4654 return Top::Throw(Heap::illegal_argument_symbol());
4655 }
4656
4657 // Get the number of steps.
4658 int step_count = NumberToInt32(args[2]);
4659 if (step_count < 1) {
4660 return Top::Throw(Heap::illegal_argument_symbol());
4661 }
4662
4663 // Prepare step.
4664 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
4665 return Heap::undefined_value();
4666}
4667
4668
4669// Clear all stepping set by PrepareStep.
4670static Object* Runtime_ClearStepping(Arguments args) {
4671 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004672 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673 Debug::ClearStepping();
4674 return Heap::undefined_value();
4675}
4676
4677
4678// Creates a copy of the with context chain. The copy of the context chain is
4679// is linked to the function context supplied.
4680static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
4681 Handle<Context> function_context) {
4682 // At the bottom of the chain. Return the function context to link to.
4683 if (context_chain->is_function_context()) {
4684 return function_context;
4685 }
4686
4687 // Recursively copy the with contexts.
4688 Handle<Context> previous(context_chain->previous());
4689 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
4690 return Factory::NewWithContext(
4691 CopyWithContextChain(function_context, previous), extension);
4692}
4693
4694
4695// Helper function to find or create the arguments object for
4696// Runtime_DebugEvaluate.
4697static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
4698 Handle<JSFunction> function,
4699 Handle<Code> code,
4700 const ScopeInfo<>* sinfo,
4701 Handle<Context> function_context) {
4702 // Try to find the value of 'arguments' to pass as parameter. If it is not
4703 // found (that is the debugged function does not reference 'arguments' and
4704 // does not support eval) then create an 'arguments' object.
4705 int index;
4706 if (sinfo->number_of_stack_slots() > 0) {
4707 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
4708 if (index != -1) {
4709 return Handle<Object>(frame->GetExpression(index));
4710 }
4711 }
4712
4713 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
4714 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
4715 NULL);
4716 if (index != -1) {
4717 return Handle<Object>(function_context->get(index));
4718 }
4719 }
4720
4721 const int length = frame->GetProvidedParametersCount();
4722 Handle<Object> arguments = Factory::NewArgumentsObject(function, length);
4723 FixedArray* array = FixedArray::cast(JSObject::cast(*arguments)->elements());
4724 ASSERT(array->length() == length);
4725 for (int i = 0; i < length; i++) {
4726 array->set(i, frame->GetParameter(i));
4727 }
4728 return arguments;
4729}
4730
4731
4732// Evaluate a piece of JavaScript in the context of a stack frame for
4733// debugging. This is acomplished by creating a new context which in its
4734// extension part has all the parameters and locals of the function on the
4735// stack frame. A function which calls eval with the code to evaluate is then
4736// compiled in this context and called in this context. As this context
4737// replaces the context of the function on the stack frame a new (empty)
4738// function is created as well to be used as the closure for the context.
4739// This function and the context acts as replacements for the function on the
4740// stack frame presenting the same view of the values of parameters and
4741// local variables as if the piece of JavaScript was evaluated at the point
4742// where the function on the stack frame is currently stopped.
4743static Object* Runtime_DebugEvaluate(Arguments args) {
4744 HandleScope scope;
4745
4746 // Check the execution state and decode arguments frame and source to be
4747 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004748 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749 Object* check_result = Runtime_CheckExecutionState(args);
4750 if (check_result->IsFailure()) return check_result;
4751 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
4752 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004753 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
4754
4755 // Handle the processing of break.
4756 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757
4758 // Get the frame where the debugging is performed.
4759 StackFrame::Id id = UnwrapFrameId(wrapped_id);
4760 JavaScriptFrameIterator it(id);
4761 JavaScriptFrame* frame = it.frame();
4762 Handle<JSFunction> function(JSFunction::cast(frame->function()));
4763 Handle<Code> code(function->code());
4764 ScopeInfo<> sinfo(*code);
4765
4766 // Traverse the saved contexts chain to find the active context for the
4767 // selected frame.
4768 SaveContext* save = Top::save_context();
4769 while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
4770 save = save->prev();
4771 }
4772 ASSERT(save != NULL);
4773 SaveContext savex;
4774 Top::set_context(*(save->context()));
4775 Top::set_security_context(*(save->security_context()));
4776
4777 // Create the (empty) function replacing the function on the stack frame for
4778 // the purpose of evaluating in the context created below. It is important
4779 // that this function does not describe any parameters and local variables
4780 // in the context. If it does then this will cause problems with the lookup
4781 // in Context::Lookup, where context slots for parameters and local variables
4782 // are looked at before the extension object.
4783 Handle<JSFunction> go_between =
4784 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
4785 go_between->set_context(function->context());
4786#ifdef DEBUG
4787 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
4788 ASSERT(go_between_sinfo.number_of_parameters() == 0);
4789 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
4790#endif
4791
4792 // Allocate and initialize a context extension object with all the
4793 // arguments, stack locals heap locals and extension properties of the
4794 // debugged function.
4795 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
4796 // First fill all parameters to the context extension.
4797 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
4798 SetProperty(context_ext,
4799 sinfo.parameter_name(i),
4800 Handle<Object>(frame->GetParameter(i)), NONE);
4801 }
4802 // Second fill all stack locals to the context extension.
4803 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
4804 SetProperty(context_ext,
4805 sinfo.stack_slot_name(i),
4806 Handle<Object>(frame->GetExpression(i)), NONE);
4807 }
4808 // Third fill all context locals to the context extension.
4809 Handle<Context> frame_context(Context::cast(frame->context()));
4810 Handle<Context> function_context(frame_context->fcontext());
4811 for (int i = Context::MIN_CONTEXT_SLOTS;
4812 i < sinfo.number_of_context_slots();
4813 ++i) {
4814 int context_index =
4815 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
4816 SetProperty(context_ext,
4817 sinfo.context_slot_name(i),
4818 Handle<Object>(function_context->get(context_index)), NONE);
4819 }
4820 // Finally copy any properties from the function context extension. This will
4821 // be variables introduced by eval.
4822 if (function_context->extension() != NULL &&
4823 !function_context->IsGlobalContext()) {
4824 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
4825 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
4826 for (int i = 0; i < keys->length(); i++) {
4827 // Names of variables introduced by eval are strings.
4828 ASSERT(keys->get(i)->IsString());
4829 Handle<String> key(String::cast(keys->get(i)));
4830 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
4831 }
4832 }
4833
4834 // Allocate a new context for the debug evaluation and set the extension
4835 // object build.
4836 Handle<Context> context =
4837 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
4838 context->set_extension(*context_ext);
4839 // Copy any with contexts present and chain them in front of this context.
4840 context = CopyWithContextChain(frame_context, context);
4841
4842 // Wrap the evaluation statement in a new function compiled in the newly
4843 // created context. The function has one parameter which has to be called
4844 // 'arguments'. This it to have access to what would have been 'arguments' in
4845 // the function beeing debugged.
4846 // function(arguments,__source__) {return eval(__source__);}
4847 static const char* source_str =
4848 "function(arguments,__source__){return eval(__source__);}";
4849 static const int source_str_length = strlen(source_str);
4850 Handle<String> function_source =
4851 Factory::NewStringFromAscii(Vector<const char>(source_str,
4852 source_str_length));
4853 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00004854 Compiler::CompileEval(function_source, 0, context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004855 if (boilerplate.is_null()) return Failure::Exception();
4856 Handle<JSFunction> compiled_function =
4857 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4858
4859 // Invoke the result of the compilation to get the evaluation function.
4860 bool has_pending_exception;
4861 Handle<Object> receiver(frame->receiver());
4862 Handle<Object> evaluation_function =
4863 Execution::Call(compiled_function, receiver, 0, NULL,
4864 &has_pending_exception);
4865
4866 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
4867 function_context);
4868
4869 // Invoke the evaluation function and return the result.
4870 const int argc = 2;
4871 Object** argv[argc] = { arguments.location(),
4872 Handle<Object>::cast(source).location() };
4873 Handle<Object> result =
4874 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
4875 argc, argv, &has_pending_exception);
4876 return *result;
4877}
4878
4879
4880static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
4881 HandleScope scope;
4882
4883 // Check the execution state and decode arguments frame and source to be
4884 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004885 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886 Object* check_result = Runtime_CheckExecutionState(args);
4887 if (check_result->IsFailure()) return check_result;
4888 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004889 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
4890
4891 // Handle the processing of break.
4892 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893
4894 // Enter the top context from before the debugger was invoked.
4895 SaveContext save;
4896 SaveContext* top = &save;
4897 while (top != NULL && *top->context() == *Debug::debug_context()) {
4898 top = top->prev();
4899 }
4900 if (top != NULL) {
4901 Top::set_context(*top->context());
4902 Top::set_security_context(*top->security_context());
4903 }
4904
4905 // Get the global context now set to the top context from before the
4906 // debugger was invoked.
4907 Handle<Context> context = Top::global_context();
4908
4909 // Compile the source to be evaluated.
ager@chromium.org236ad962008-09-25 09:45:57 +00004910 Handle<JSFunction> boilerplate(Compiler::CompileEval(source, 0, true));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004911 if (boilerplate.is_null()) return Failure::Exception();
4912 Handle<JSFunction> compiled_function =
4913 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
4914 context));
4915
4916 // Invoke the result of the compilation to get the evaluation function.
4917 bool has_pending_exception;
4918 Handle<Object> receiver = Top::global();
4919 Handle<Object> result =
4920 Execution::Call(compiled_function, receiver, 0, NULL,
4921 &has_pending_exception);
4922 return *result;
4923}
4924
4925
4926// Helper function used by Runtime_DebugGetLoadedScripts below.
4927static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
4928 NoHandleAllocation ha;
4929 AssertNoAllocation no_alloc;
4930
4931 // Get hold of the current empty script.
4932 Context* context = Top::context()->global_context();
4933 Script* empty = context->empty_script();
4934
4935 // Scan heap for Script objects.
4936 int count = 0;
4937 HeapIterator iterator;
4938 while (iterator.has_next()) {
4939 HeapObject* obj = iterator.next();
4940 ASSERT(obj != NULL);
4941 if (obj->IsScript() && obj != empty) {
4942 if (instances != NULL && count < instances_size) {
4943 instances->set(count, obj);
4944 }
4945 count++;
4946 }
4947 }
4948
4949 return count;
4950}
4951
4952
4953static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
4954 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004955 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004956
4957 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
4958 // rid of all the cached script wrappes and the second gets rid of the
4959 // scripts which is no longer referenced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004960 Heap::CollectAllGarbage();
4961 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004962
4963 // Get the number of scripts.
4964 int count;
4965 count = DebugGetLoadedScripts(NULL, 0);
4966
4967 // Allocate an array to hold the result.
4968 Handle<FixedArray> instances = Factory::NewFixedArray(count);
4969
4970 // Fill the script objects.
4971 count = DebugGetLoadedScripts(*instances, count);
4972
4973 // Convert the script objects to proper JS objects.
4974 for (int i = 0; i < count; i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004975 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
4976 // Get the script wrapper in a local handle before calling GetScriptWrapper,
4977 // because using
4978 // instances->set(i, *GetScriptWrapper(script))
4979 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
4980 // already have deferenced the instances handle.
4981 Handle<JSValue> wrapper = GetScriptWrapper(script);
4982 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004983 }
4984
4985 // Return result as a JS array.
4986 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
4987 Handle<JSArray>::cast(result)->SetContent(*instances);
4988 return *result;
4989}
4990
4991
4992// Helper function used by Runtime_DebugReferencedBy below.
4993static int DebugReferencedBy(JSObject* target,
4994 Object* instance_filter, int max_references,
4995 FixedArray* instances, int instances_size,
4996 JSFunction* context_extension_function,
4997 JSFunction* arguments_function) {
4998 NoHandleAllocation ha;
4999 AssertNoAllocation no_alloc;
5000
5001 // Iterate the heap.
5002 int count = 0;
5003 JSObject* last = NULL;
5004 HeapIterator iterator;
5005 while (iterator.has_next() &&
5006 (max_references == 0 || count < max_references)) {
5007 // Only look at all JSObjects.
5008 HeapObject* heap_obj = iterator.next();
5009 if (heap_obj->IsJSObject()) {
5010 // Skip context extension objects and argument arrays as these are
5011 // checked in the context of functions using them.
5012 JSObject* obj = JSObject::cast(heap_obj);
5013 if (obj->map()->constructor() == context_extension_function ||
5014 obj->map()->constructor() == arguments_function) {
5015 continue;
5016 }
5017
5018 // Check if the JS object has a reference to the object looked for.
5019 if (obj->ReferencesObject(target)) {
5020 // Check instance filter if supplied. This is normally used to avoid
5021 // references from mirror objects (see Runtime_IsInPrototypeChain).
5022 if (!instance_filter->IsUndefined()) {
5023 Object* V = obj;
5024 while (true) {
5025 Object* prototype = V->GetPrototype();
5026 if (prototype->IsNull()) {
5027 break;
5028 }
5029 if (instance_filter == prototype) {
5030 obj = NULL; // Don't add this object.
5031 break;
5032 }
5033 V = prototype;
5034 }
5035 }
5036
5037 if (obj != NULL) {
5038 // Valid reference found add to instance array if supplied an update
5039 // count.
5040 if (instances != NULL && count < instances_size) {
5041 instances->set(count, obj);
5042 }
5043 last = obj;
5044 count++;
5045 }
5046 }
5047 }
5048 }
5049
5050 // Check for circular reference only. This can happen when the object is only
5051 // referenced from mirrors and has a circular reference in which case the
5052 // object is not really alive and would have been garbage collected if not
5053 // referenced from the mirror.
5054 if (count == 1 && last == target) {
5055 count = 0;
5056 }
5057
5058 // Return the number of referencing objects found.
5059 return count;
5060}
5061
5062
5063// Scan the heap for objects with direct references to an object
5064// args[0]: the object to find references to
5065// args[1]: constructor function for instances to exclude (Mirror)
5066// args[2]: the the maximum number of objects to return
5067static Object* Runtime_DebugReferencedBy(Arguments args) {
5068 ASSERT(args.length() == 3);
5069
5070 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005071 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005072
5073 // Check parameters.
5074 CONVERT_CHECKED(JSObject, target, args[0]);
5075 Object* instance_filter = args[1];
5076 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
5077 instance_filter->IsJSObject());
5078 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
5079 RUNTIME_ASSERT(max_references >= 0);
5080
5081 // Get the constructor function for context extension and arguments array.
5082 JSFunction* context_extension_function =
5083 Top::context()->global_context()->context_extension_function();
5084 JSObject* arguments_boilerplate =
5085 Top::context()->global_context()->arguments_boilerplate();
5086 JSFunction* arguments_function =
5087 JSFunction::cast(arguments_boilerplate->map()->constructor());
5088
5089 // Get the number of referencing objects.
5090 int count;
5091 count = DebugReferencedBy(target, instance_filter, max_references,
5092 NULL, 0,
5093 context_extension_function, arguments_function);
5094
5095 // Allocate an array to hold the result.
5096 Object* object = Heap::AllocateFixedArray(count);
5097 if (object->IsFailure()) return object;
5098 FixedArray* instances = FixedArray::cast(object);
5099
5100 // Fill the referencing objects.
5101 count = DebugReferencedBy(target, instance_filter, max_references,
5102 instances, count,
5103 context_extension_function, arguments_function);
5104
5105 // Return result as JS array.
5106 Object* result =
5107 Heap::AllocateJSObject(
5108 Top::context()->global_context()->array_function());
5109 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5110 return result;
5111}
5112
5113
5114// Helper function used by Runtime_DebugConstructedBy below.
5115static int DebugConstructedBy(JSFunction* constructor, int max_references,
5116 FixedArray* instances, int instances_size) {
5117 AssertNoAllocation no_alloc;
5118
5119 // Iterate the heap.
5120 int count = 0;
5121 HeapIterator iterator;
5122 while (iterator.has_next() &&
5123 (max_references == 0 || count < max_references)) {
5124 // Only look at all JSObjects.
5125 HeapObject* heap_obj = iterator.next();
5126 if (heap_obj->IsJSObject()) {
5127 JSObject* obj = JSObject::cast(heap_obj);
5128 if (obj->map()->constructor() == constructor) {
5129 // Valid reference found add to instance array if supplied an update
5130 // count.
5131 if (instances != NULL && count < instances_size) {
5132 instances->set(count, obj);
5133 }
5134 count++;
5135 }
5136 }
5137 }
5138
5139 // Return the number of referencing objects found.
5140 return count;
5141}
5142
5143
5144// Scan the heap for objects constructed by a specific function.
5145// args[0]: the constructor to find instances of
5146// args[1]: the the maximum number of objects to return
5147static Object* Runtime_DebugConstructedBy(Arguments args) {
5148 ASSERT(args.length() == 2);
5149
5150 // First perform a full GC in order to avoid dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005151 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152
5153 // Check parameters.
5154 CONVERT_CHECKED(JSFunction, constructor, args[0]);
5155 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
5156 RUNTIME_ASSERT(max_references >= 0);
5157
5158 // Get the number of referencing objects.
5159 int count;
5160 count = DebugConstructedBy(constructor, max_references, NULL, 0);
5161
5162 // Allocate an array to hold the result.
5163 Object* object = Heap::AllocateFixedArray(count);
5164 if (object->IsFailure()) return object;
5165 FixedArray* instances = FixedArray::cast(object);
5166
5167 // Fill the referencing objects.
5168 count = DebugConstructedBy(constructor, max_references, instances, count);
5169
5170 // Return result as JS array.
5171 Object* result =
5172 Heap::AllocateJSObject(
5173 Top::context()->global_context()->array_function());
5174 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5175 return result;
5176}
5177
5178
5179static Object* Runtime_GetPrototype(Arguments args) {
5180 ASSERT(args.length() == 1);
5181
5182 CONVERT_CHECKED(JSObject, obj, args[0]);
5183
5184 return obj->GetPrototype();
5185}
5186
5187
5188static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005189 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 CPU::DebugBreak();
5191 return Heap::undefined_value();
5192}
5193
5194
5195// Finds the script object from the script data. NOTE: This operation uses
5196// heap traversal to find the function generated for the source position
5197// for the requested break point. For lazily compiled functions several heap
5198// traversals might be required rendering this operation as a rather slow
5199// operation. However for setting break points which is normally done through
5200// some kind of user interaction the performance is not crucial.
5201static Handle<Object> Runtime_GetScriptFromScriptName(
5202 Handle<String> script_name) {
5203 // Scan the heap for Script objects to find the script with the requested
5204 // script data.
5205 Handle<Script> script;
5206 HeapIterator iterator;
5207 while (script.is_null() && iterator.has_next()) {
5208 HeapObject* obj = iterator.next();
5209 // If a script is found check if it has the script data requested.
5210 if (obj->IsScript()) {
5211 if (Script::cast(obj)->name()->IsString()) {
5212 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
5213 script = Handle<Script>(Script::cast(obj));
5214 }
5215 }
5216 }
5217 }
5218
5219 // If no script with the requested script data is found return undefined.
5220 if (script.is_null()) return Factory::undefined_value();
5221
5222 // Return the script found.
5223 return GetScriptWrapper(script);
5224}
5225
5226
5227// Get the script object from script data. NOTE: Regarding performance
5228// see the NOTE for GetScriptFromScriptData.
5229// args[0]: script data for the script to find the source for
5230static Object* Runtime_GetScript(Arguments args) {
5231 HandleScope scope;
5232
5233 ASSERT(args.length() == 1);
5234
5235 CONVERT_CHECKED(String, script_name, args[0]);
5236
5237 // Find the requested script.
5238 Handle<Object> result =
5239 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
5240 return *result;
5241}
5242
5243
5244static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
5245#ifdef DEBUG
5246 HandleScope scope;
5247 ASSERT(args.length() == 1);
5248 // Get the function and make sure it is compiled.
5249 CONVERT_ARG_CHECKED(JSFunction, func, 0);
5250 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
5251 return Failure::Exception();
5252 }
5253 func->code()->PrintLn();
5254#endif // DEBUG
5255 return Heap::undefined_value();
5256}
5257
5258
5259static Object* Runtime_Abort(Arguments args) {
5260 ASSERT(args.length() == 2);
5261 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
5262 Smi::cast(args[1])->value());
5263 Top::PrintStack();
5264 OS::Abort();
5265 UNREACHABLE();
5266 return NULL;
5267}
5268
5269
kasper.lund44510672008-07-25 07:37:58 +00005270#ifdef DEBUG
5271// ListNatives is ONLY used by the fuzz-natives.js in debug mode
5272// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005273static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005274 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005275 HandleScope scope;
5276 Handle<JSArray> result = Factory::NewJSArray(0);
5277 int index = 0;
5278#define ADD_ENTRY(Name, argc) \
5279 { \
5280 HandleScope inner; \
5281 Handle<String> name = \
5282 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
5283 Handle<JSArray> pair = Factory::NewJSArray(0); \
5284 SetElement(pair, 0, name); \
5285 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
5286 SetElement(result, index++, pair); \
5287 }
5288 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
5289#undef ADD_ENTRY
5290 return *result;
5291}
kasper.lund44510672008-07-25 07:37:58 +00005292#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005293
5294
5295static Object* Runtime_IS_VAR(Arguments args) {
5296 UNREACHABLE(); // implemented as macro in the parser
5297 return NULL;
5298}
5299
5300
5301// ----------------------------------------------------------------------------
5302// Implementation of Runtime
5303
5304#define F(name, nargs) \
5305 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
5306 static_cast<int>(Runtime::k##name) },
5307
5308static Runtime::Function Runtime_functions[] = {
5309 RUNTIME_FUNCTION_LIST(F)
5310 { NULL, NULL, NULL, 0, -1 }
5311};
5312
5313#undef F
5314
5315
5316Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
5317 ASSERT(0 <= fid && fid < kNofFunctions);
5318 return &Runtime_functions[fid];
5319}
5320
5321
5322Runtime::Function* Runtime::FunctionForName(const char* name) {
5323 for (Function* f = Runtime_functions; f->name != NULL; f++) {
5324 if (strcmp(f->name, name) == 0) {
5325 return f;
5326 }
5327 }
5328 return NULL;
5329}
5330
5331
5332void Runtime::PerformGC(Object* result) {
5333 Failure* failure = Failure::cast(result);
5334 // Try to do a garbage collection; ignore it if it fails. The C
5335 // entry stub will throw an out-of-memory exception in that case.
5336 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
5337}
5338
5339
5340} } // namespace v8::internal