blob: b0e1a057da4b4384cedff7372fd0a04775c14988 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000119// Assert that the given argument has a valid value for a LanguageMode
120// and store it in a LanguageMode variable with the given name.
121#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
122 ASSERT(args[index]->IsSmi()); \
123 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
124 args.smi_at(index) == STRICT_MODE || \
125 args.smi_at(index) == EXTENDED_MODE); \
126 LanguageMode name = \
127 static_cast<LanguageMode>(args.smi_at(index));
128
129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
131 JSObject* boilerplate) {
132 StackLimitCheck check(isolate);
133 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 JSObject* copy = JSObject::cast(result);
141
142 // Deep copy local properties.
143 if (copy->HasFastProperties()) {
144 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 for (int i = 0; i < properties->length(); i++) {
146 Object* value = properties->get(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000155 int nof = copy->map()->inobject_properties();
156 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 Object* value = copy->InObjectPropertyAt(i);
158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000164 }
165 }
166 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 FixedArray* names = FixedArray::cast(result);
172 copy->GetLocalPropertyNames(names, 0);
173 for (int i = 0; i < names->length(); i++) {
174 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000176 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 // Only deep copy fields from the object literal expression.
179 // In particular, don't try to copy the length attribute of
180 // an array.
181 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000182 Object* value =
183 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 if (!maybe_result->ToObject(&result)) return maybe_result;
188 }
189 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000190 // Creating object copy for literals. No strict mode needed.
191 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 }
195 }
196 }
197
198 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000200 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000202 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000203 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 if (elements->map() == heap->fixed_cow_array_map()) {
206 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207#ifdef DEBUG
208 for (int i = 0; i < elements->length(); i++) {
209 ASSERT(!elements->get(i)->IsJSObject());
210 }
211#endif
212 } else {
213 for (int i = 0; i < elements->length(); i++) {
214 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 ASSERT(value->IsSmi() ||
216 value->IsTheHole() ||
217 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000218 if (value->IsJSObject()) {
219 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
221 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000222 if (!maybe_result->ToObject(&result)) return maybe_result;
223 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000224 elements->set(i, result);
225 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000226 }
227 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000228 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000230 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000231 NumberDictionary* element_dictionary = copy->element_dictionary();
232 int capacity = element_dictionary->Capacity();
233 for (int i = 0; i < capacity; i++) {
234 Object* k = element_dictionary->KeyAt(i);
235 if (element_dictionary->IsKey(k)) {
236 Object* value = element_dictionary->ValueAt(i);
237 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
240 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000243 element_dictionary->ValueAtPut(i, result);
244 }
245 }
246 }
247 break;
248 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000249 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000250 UNIMPLEMENTED();
251 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000252 case EXTERNAL_PIXEL_ELEMENTS:
253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000262 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000263 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 }
265 return copy;
266}
267
268
ager@chromium.org236ad962008-09-25 09:45:57 +0000269static Handle<Map> ComputeObjectLiteralMap(
270 Handle<Context> context,
271 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000272 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 int properties_length = constant_properties->length();
275 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000276 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000277 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 for (int p = 0; p != properties_length; p += 2) {
280 Object* key = constant_properties->get(p);
281 uint32_t element_index = 0;
282 if (key->IsSymbol()) {
283 number_of_symbol_keys++;
284 } else if (key->ToArrayIndex(&element_index)) {
285 // An index key does not require space in the property backing store.
286 number_of_properties--;
287 } else {
288 // Bail out as a non-symbol non-index key makes caching impossible.
289 // ASSERT to make sure that the if condition after the loop is false.
290 ASSERT(number_of_symbol_keys != number_of_properties);
291 break;
292 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000294 // If we only have symbols and array indices among keys then we can
295 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 if ((number_of_symbol_keys == number_of_properties) &&
298 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Handle<FixedArray> keys =
301 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000302 if (number_of_symbol_keys > 0) {
303 int index = 0;
304 for (int p = 0; p < properties_length; p += 2) {
305 Object* key = constant_properties->get(p);
306 if (key->IsSymbol()) {
307 keys->set(index++, key);
308 }
309 }
310 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000312 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 }
315 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000316 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000318 Handle<Map>(context->object_function()->initial_map()),
319 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000320}
321
322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000325 Handle<FixedArray> literals,
326 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000327
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000328
329static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000332 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 bool should_have_fast_elements,
334 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000335 // Get the global context from the literals array. This is the
336 // context in which the function was created and we use the object
337 // function from this context to create the object literal. We do
338 // not use the object function from the current global context
339 // because this might be the object function from another context
340 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000341 Handle<Context> context =
342 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 // In case we have function literals, we want the object to be in
345 // slow properties mode for now. We don't go in the map cache because
346 // maps with constant functions can't be shared if the functions are
347 // not the same (which is the common case).
348 bool is_result_from_cache = false;
349 Handle<Map> map = has_function_literal
350 ? Handle<Map>(context->object_function()->initial_map())
351 : ComputeObjectLiteralMap(context,
352 constant_properties,
353 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000356
357 // Normalize the elements of the boilerplate to save space if needed.
358 if (!should_have_fast_elements) NormalizeElements(boilerplate);
359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 // Add the constant properties to the boilerplate.
361 int length = constant_properties->length();
362 bool should_transform =
363 !is_result_from_cache && boilerplate->HasFastProperties();
364 if (should_transform || has_function_literal) {
365 // Normalize the properties of object to avoid n^2 behavior
366 // when extending the object multiple properties. Indicate the number of
367 // properties to be added.
368 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
369 }
370
371 for (int index = 0; index < length; index +=2) {
372 Handle<Object> key(constant_properties->get(index+0), isolate);
373 Handle<Object> value(constant_properties->get(index+1), isolate);
374 if (value->IsFixedArray()) {
375 // The value contains the constant_properties of a
376 // simple object or array literal.
377 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
378 value = CreateLiteralBoilerplate(isolate, literals, array);
379 if (value.is_null()) return value;
380 }
381 Handle<Object> result;
382 uint32_t element_index = 0;
383 if (key->IsSymbol()) {
384 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
385 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000386 result = SetOwnElement(boilerplate,
387 element_index,
388 value,
389 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 Handle<String> name(String::cast(*key));
392 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000393 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
394 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 } else if (key->ToArrayIndex(&element_index)) {
397 // Array index (uint32).
398 result = SetOwnElement(boilerplate,
399 element_index,
400 value,
401 kNonStrictMode);
402 } else {
403 // Non-uint32 number.
404 ASSERT(key->IsNumber());
405 double num = key->Number();
406 char arr[100];
407 Vector<char> buffer(arr, ARRAY_SIZE(arr));
408 const char* str = DoubleToCString(num, buffer);
409 Handle<String> name =
410 isolate->factory()->NewStringFromAscii(CStrVector(str));
411 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
412 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 // If setting the property on the boilerplate throws an
415 // exception, the exception is converted to an empty handle in
416 // the handle based operations. In that case, we need to
417 // convert back to an exception.
418 if (result.is_null()) return result;
419 }
420
421 // Transform to fast properties if necessary. For object literals with
422 // containing function literals we defer this operation until after all
423 // computed properties have been assigned so that we can generate
424 // constant function properties.
425 if (should_transform && !has_function_literal) {
426 TransformToFastProperties(boilerplate,
427 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 }
429
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000430 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000431}
432
433
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000434static const int kSmiOnlyLiteralMinimumLength = 1024;
435
436
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000437// static
438Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 Handle<FixedArray> literals,
441 Handle<FixedArray> elements) {
442 // Create the JSArray.
443 Handle<JSFunction> constructor(
444 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445 Handle<JSArray> object =
446 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000448 ElementsKind constant_elements_kind =
449 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
450 Handle<FixedArrayBase> constant_elements_values(
451 FixedArrayBase::cast(elements->get(1)));
452
453 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
454 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
455 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
456 constant_elements_kind > object->GetElementsKind();
457
458 if (!FLAG_smi_only_arrays &&
459 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
460 constant_elements_kind != object->GetElementsKind()) {
461 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462 }
463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 // If the ElementsKind of the constant values of the array literal are less
465 // specific than the ElementsKind of the boilerplate array object, change the
466 // boilerplate array object's map to reflect that kind.
467 if (allow_literal_kind_transition) {
468 Handle<Map> transitioned_array_map =
469 isolate->factory()->GetElementsTransitionMap(object,
470 constant_elements_kind);
471 object->set_map(*transitioned_array_map);
472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<FixedArrayBase> copied_elements_values;
475 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 ASSERT(FLAG_smi_only_arrays);
477 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
478 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
481 constant_elements_kind == FAST_ELEMENTS);
482 const bool is_cow =
483 (constant_elements_values->map() ==
484 isolate->heap()->fixed_cow_array_map());
485 if (is_cow) {
486 copied_elements_values = constant_elements_values;
487#if DEBUG
488 Handle<FixedArray> fixed_array_values =
489 Handle<FixedArray>::cast(copied_elements_values);
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
492 }
493#endif
494 } else {
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(constant_elements_values);
497 Handle<FixedArray> fixed_array_values_copy =
498 isolate->factory()->CopyFixedArray(fixed_array_values);
499 copied_elements_values = fixed_array_values_copy;
500 for (int i = 0; i < fixed_array_values->length(); i++) {
501 Object* current = fixed_array_values->get(i);
502 if (current->IsFixedArray()) {
503 // The value contains the constant_properties of a
504 // simple object or array literal.
505 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
506 Handle<Object> result =
507 CreateLiteralBoilerplate(isolate, literals, fa);
508 if (result.is_null()) return result;
509 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000510 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 }
513 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000514 object->set_elements(*copied_elements_values);
515 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 return object;
517}
518
519
520static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 Handle<FixedArray> literals,
523 Handle<FixedArray> array) {
524 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 return CreateObjectLiteralBoilerplate(isolate,
529 literals,
530 elements,
531 true,
532 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return CreateObjectLiteralBoilerplate(isolate,
535 literals,
536 elements,
537 false,
538 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000540 return Runtime::CreateArrayLiteralBoilerplate(
541 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000542 default:
543 UNREACHABLE();
544 return Handle<Object>::null();
545 }
546}
547
548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000549RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000553 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000555 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
557 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000558
559 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<Object> boilerplate(literals->get(literals_index), isolate);
561 if (*boilerplate == isolate->heap()->undefined_value()) {
562 boilerplate = CreateObjectLiteralBoilerplate(isolate,
563 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000564 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 should_have_fast_elements,
566 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000567 if (boilerplate.is_null()) return Failure::Exception();
568 // Update the functions literal and return the boilerplate.
569 literals->set(literals_index, *boilerplate);
570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000572}
573
574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000575RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000577 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000579 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000581 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
583 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584
585 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 Handle<Object> boilerplate(literals->get(literals_index), isolate);
587 if (*boilerplate == isolate->heap()->undefined_value()) {
588 boilerplate = CreateObjectLiteralBoilerplate(isolate,
589 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000590 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 should_have_fast_elements,
592 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593 if (boilerplate.is_null()) return Failure::Exception();
594 // Update the functions literal and return the boilerplate.
595 literals->set(literals_index, *boilerplate);
596 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000598}
599
600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000601RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603 ASSERT(args.length() == 3);
604 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000605 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000606 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
607
608 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 Handle<Object> boilerplate(literals->get(literals_index), isolate);
610 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000611 boilerplate =
612 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000613 if (boilerplate.is_null()) return Failure::Exception();
614 // Update the functions literal and return the boilerplate.
615 literals->set(literals_index, *boilerplate);
616 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000617 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000618}
619
620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000621RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 ASSERT(args.length() == 3);
624 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000625 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000626 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
627
628 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000629 Handle<Object> boilerplate(literals->get(literals_index), isolate);
630 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000631 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000632 boilerplate =
633 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000634 if (boilerplate.is_null()) return Failure::Exception();
635 // Update the functions literal and return the boilerplate.
636 literals->set(literals_index, *boilerplate);
637 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000638 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000640 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000641 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643}
644
645
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000646RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
647 ASSERT(args.length() == 2);
648 Object* handler = args[0];
649 Object* prototype = args[1];
650 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000651 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000652 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
653}
654
655
lrn@chromium.org34e60782011-09-15 07:25:40 +0000656RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
657 ASSERT(args.length() == 4);
658 Object* handler = args[0];
659 Object* call_trap = args[1];
660 Object* construct_trap = args[2];
661 Object* prototype = args[3];
662 Object* used_prototype =
663 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
664 return isolate->heap()->AllocateJSFunctionProxy(
665 handler, call_trap, construct_trap, used_prototype);
666}
667
668
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
670 ASSERT(args.length() == 1);
671 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000672 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000673}
674
675
lrn@chromium.org34e60782011-09-15 07:25:40 +0000676RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
677 ASSERT(args.length() == 1);
678 Object* obj = args[0];
679 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
680}
681
682
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
684 ASSERT(args.length() == 1);
685 CONVERT_CHECKED(JSProxy, proxy, args[0]);
686 return proxy->handler();
687}
688
689
lrn@chromium.org34e60782011-09-15 07:25:40 +0000690RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
691 ASSERT(args.length() == 1);
692 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
693 return proxy->call_trap();
694}
695
696
697RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
698 ASSERT(args.length() == 1);
699 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
700 return proxy->construct_trap();
701}
702
703
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000704RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
705 ASSERT(args.length() == 1);
706 CONVERT_CHECKED(JSProxy, proxy, args[0]);
707 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000708 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000709}
710
711
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000712RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
713 HandleScope scope(isolate);
714 ASSERT(args.length() == 1);
715 CONVERT_ARG_CHECKED(JSSet, holder, 0);
716 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
717 holder->set_table(*table);
718 return *holder;
719}
720
721
722RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
723 HandleScope scope(isolate);
724 ASSERT(args.length() == 2);
725 CONVERT_ARG_CHECKED(JSSet, holder, 0);
726 Handle<Object> key(args[1]);
727 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
728 table = ObjectHashSetAdd(table, key);
729 holder->set_table(*table);
730 return isolate->heap()->undefined_symbol();
731}
732
733
734RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
735 HandleScope scope(isolate);
736 ASSERT(args.length() == 2);
737 CONVERT_ARG_CHECKED(JSSet, holder, 0);
738 Handle<Object> key(args[1]);
739 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
740 return isolate->heap()->ToBoolean(table->Contains(*key));
741}
742
743
744RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
745 HandleScope scope(isolate);
746 ASSERT(args.length() == 2);
747 CONVERT_ARG_CHECKED(JSSet, holder, 0);
748 Handle<Object> key(args[1]);
749 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
750 table = ObjectHashSetRemove(table, key);
751 holder->set_table(*table);
752 return isolate->heap()->undefined_symbol();
753}
754
755
756RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
757 HandleScope scope(isolate);
758 ASSERT(args.length() == 1);
759 CONVERT_ARG_CHECKED(JSMap, holder, 0);
760 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
761 holder->set_table(*table);
762 return *holder;
763}
764
765
766RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
767 HandleScope scope(isolate);
768 ASSERT(args.length() == 2);
769 CONVERT_ARG_CHECKED(JSMap, holder, 0);
770 Handle<Object> key(args[1]);
771 return ObjectHashTable::cast(holder->table())->Lookup(*key);
772}
773
774
775RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
776 HandleScope scope(isolate);
777 ASSERT(args.length() == 3);
778 CONVERT_ARG_CHECKED(JSMap, holder, 0);
779 Handle<Object> key(args[1]);
780 Handle<Object> value(args[2]);
781 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
782 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
783 holder->set_table(*new_table);
784 return *value;
785}
786
787
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000788RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
789 HandleScope scope(isolate);
790 ASSERT(args.length() == 1);
791 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
792 ASSERT(weakmap->map()->inobject_properties() == 0);
793 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
794 weakmap->set_table(*table);
795 weakmap->set_next(Smi::FromInt(0));
796 return *weakmap;
797}
798
799
800RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
801 NoHandleAllocation ha;
802 ASSERT(args.length() == 2);
803 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000804 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
805 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806}
807
808
809RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
810 HandleScope scope(isolate);
811 ASSERT(args.length() == 3);
812 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000813 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000814 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000815 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000816 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
817 weakmap->set_table(*new_table);
818 return *value;
819}
820
821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000822RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 NoHandleAllocation ha;
824 ASSERT(args.length() == 1);
825 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000826 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 return JSObject::cast(obj)->class_name();
828}
829
ager@chromium.org7c537e22008-10-16 08:43:32 +0000830
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000831RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
832 NoHandleAllocation ha;
833 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000834 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
835 Object* obj = input_obj;
836 // We don't expect access checks to be needed on JSProxy objects.
837 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000838 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000839 if (obj->IsAccessCheckNeeded() &&
840 !isolate->MayNamedAccess(JSObject::cast(obj),
841 isolate->heap()->Proto_symbol(),
842 v8::ACCESS_GET)) {
843 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
844 return isolate->heap()->undefined_value();
845 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000846 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000847 } while (obj->IsJSObject() &&
848 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849 return obj;
850}
851
852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000853RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000854 NoHandleAllocation ha;
855 ASSERT(args.length() == 2);
856 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
857 Object* O = args[0];
858 Object* V = args[1];
859 while (true) {
860 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 if (prototype->IsNull()) return isolate->heap()->false_value();
862 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 V = prototype;
864 }
865}
866
867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000868RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000870 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000871 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873}
874
875
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000876// Recursively traverses hidden prototypes if property is not found
877static void GetOwnPropertyImplementation(JSObject* obj,
878 String* name,
879 LookupResult* result) {
880 obj->LocalLookupRealNamedProperty(name, result);
881
882 if (!result->IsProperty()) {
883 Object* proto = obj->GetPrototype();
884 if (proto->IsJSObject() &&
885 JSObject::cast(proto)->map()->is_hidden_prototype())
886 GetOwnPropertyImplementation(JSObject::cast(proto),
887 name, result);
888 }
889}
890
891
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000892static bool CheckAccessException(LookupResult* result,
893 v8::AccessType access_type) {
894 if (result->type() == CALLBACKS) {
895 Object* callback = result->GetCallbackObject();
896 if (callback->IsAccessorInfo()) {
897 AccessorInfo* info = AccessorInfo::cast(callback);
898 bool can_access =
899 (access_type == v8::ACCESS_HAS &&
900 (info->all_can_read() || info->all_can_write())) ||
901 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
902 (access_type == v8::ACCESS_SET && info->all_can_write());
903 return can_access;
904 }
905 }
906
907 return false;
908}
909
910
911static bool CheckAccess(JSObject* obj,
912 String* name,
913 LookupResult* result,
914 v8::AccessType access_type) {
915 ASSERT(result->IsProperty());
916
917 JSObject* holder = result->holder();
918 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000920 while (true) {
921 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000922 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000923 // Access check callback denied the access, but some properties
924 // can have a special permissions which override callbacks descision
925 // (currently see v8::AccessControl).
926 break;
927 }
928
929 if (current == holder) {
930 return true;
931 }
932
933 current = JSObject::cast(current->GetPrototype());
934 }
935
936 // API callbacks can have per callback access exceptions.
937 switch (result->type()) {
938 case CALLBACKS: {
939 if (CheckAccessException(result, access_type)) {
940 return true;
941 }
942 break;
943 }
944 case INTERCEPTOR: {
945 // If the object has an interceptor, try real named properties.
946 // Overwrite the result to fetch the correct property later.
947 holder->LookupRealNamedProperty(name, result);
948 if (result->IsProperty()) {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 }
953 break;
954 }
955 default:
956 break;
957 }
958
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000960 return false;
961}
962
963
964// TODO(1095): we should traverse hidden prototype hierachy as well.
965static bool CheckElementAccess(JSObject* obj,
966 uint32_t index,
967 v8::AccessType access_type) {
968 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971 }
972
973 return true;
974}
975
976
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000977// Enumerator used as indices into the array returned from GetOwnProperty
978enum PropertyDescriptorIndices {
979 IS_ACCESSOR_INDEX,
980 VALUE_INDEX,
981 GETTER_INDEX,
982 SETTER_INDEX,
983 WRITABLE_INDEX,
984 ENUMERABLE_INDEX,
985 CONFIGURABLE_INDEX,
986 DESCRIPTOR_SIZE
987};
988
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000989// Returns an array with the property description:
990// if args[1] is not a property on args[0]
991// returns undefined
992// if args[1] is a data property on args[0]
993// [false, value, Writeable, Enumerable, Configurable]
994// if args[1] is an accessor on args[0]
995// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000997 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 Heap* heap = isolate->heap();
999 HandleScope scope(isolate);
1000 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1001 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001002 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001003 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1004 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001005
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001006 // This could be an element.
1007 uint32_t index;
1008 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001009 switch (obj->HasLocalElement(index)) {
1010 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001012
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001013 case JSObject::STRING_CHARACTER_ELEMENT: {
1014 // Special handling of string objects according to ECMAScript 5
1015 // 15.5.5.2. Note that this might be a string object with elements
1016 // other than the actual string value. This is covered by the
1017 // subsequent cases.
1018 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1019 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001020 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001024 elms->set(WRITABLE_INDEX, heap->false_value());
1025 elms->set(ENUMERABLE_INDEX, heap->false_value());
1026 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001027 return *desc;
1028 }
1029
1030 case JSObject::INTERCEPTED_ELEMENT:
1031 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001033 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001034 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001035 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 elms->set(WRITABLE_INDEX, heap->true_value());
1037 elms->set(ENUMERABLE_INDEX, heap->true_value());
1038 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001039 return *desc;
1040 }
1041
1042 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001043 Handle<JSObject> holder = obj;
1044 if (obj->IsJSGlobalProxy()) {
1045 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001046 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001047 ASSERT(proto->IsJSGlobalObject());
1048 holder = Handle<JSObject>(JSObject::cast(proto));
1049 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001050 FixedArray* elements = FixedArray::cast(holder->elements());
1051 NumberDictionary* dictionary = NULL;
1052 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1053 dictionary = NumberDictionary::cast(elements->get(1));
1054 } else {
1055 dictionary = NumberDictionary::cast(elements);
1056 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 int entry = dictionary->FindEntry(index);
1058 ASSERT(entry != NumberDictionary::kNotFound);
1059 PropertyDetails details = dictionary->DetailsAt(entry);
1060 switch (details.type()) {
1061 case CALLBACKS: {
1062 // This is an accessor property with getter and/or setter.
1063 FixedArray* callbacks =
1064 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001065 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001066 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1067 elms->set(GETTER_INDEX, callbacks->get(0));
1068 }
1069 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1070 elms->set(SETTER_INDEX, callbacks->get(1));
1071 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001072 break;
1073 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001075 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001077 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001078 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001079 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001081 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001082 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001083 default:
1084 UNREACHABLE();
1085 break;
1086 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1088 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001089 return *desc;
1090 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001091 }
1092 }
1093
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001094 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001095 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001096
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001097 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001099 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001100
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001101 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001103 }
1104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1106 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001107
1108 bool is_js_accessor = (result.type() == CALLBACKS) &&
1109 (result.GetCallbackObject()->IsFixedArray());
1110
1111 if (is_js_accessor) {
1112 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114
1115 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1116 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1117 elms->set(GETTER_INDEX, structure->get(0));
1118 }
1119 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1120 elms->set(SETTER_INDEX, structure->get(1));
1121 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001122 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1124 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125
1126 PropertyAttributes attrs;
1127 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001128 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001129 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1130 if (!maybe_value->ToObject(&value)) return maybe_value;
1131 }
1132 elms->set(VALUE_INDEX, value);
1133 }
1134
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001135 return *desc;
1136}
1137
1138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001139RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001140 ASSERT(args.length() == 1);
1141 CONVERT_CHECKED(JSObject, obj, args[0]);
1142 return obj->PreventExtensions();
1143}
1144
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001146RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001147 ASSERT(args.length() == 1);
1148 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001149 if (obj->IsJSGlobalProxy()) {
1150 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001151 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001152 ASSERT(proto->IsJSGlobalObject());
1153 obj = JSObject::cast(proto);
1154 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001155 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001156}
1157
1158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001159RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001162 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1163 CONVERT_ARG_CHECKED(String, pattern, 1);
1164 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001165 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1166 if (result.is_null()) return Failure::Exception();
1167 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168}
1169
1170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001171RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001174 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001175 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001179RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180 ASSERT(args.length() == 1);
1181 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001182 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001183 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184}
1185
1186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001187RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 ASSERT(args.length() == 2);
1189 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001191 int index = field->value();
1192 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1193 InstanceType type = templ->map()->instance_type();
1194 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1195 type == OBJECT_TEMPLATE_INFO_TYPE);
1196 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001197 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001198 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1199 } else {
1200 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1201 }
1202 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203}
1204
1205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001206RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001207 ASSERT(args.length() == 1);
1208 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001209 Map* old_map = object->map();
1210 bool needs_access_checks = old_map->is_access_check_needed();
1211 if (needs_access_checks) {
1212 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001213 Object* new_map;
1214 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1215 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1216 }
ager@chromium.org32912102009-01-16 10:38:43 +00001217
1218 Map::cast(new_map)->set_is_access_check_needed(false);
1219 object->set_map(Map::cast(new_map));
1220 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001221 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001222}
1223
1224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001225RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001226 ASSERT(args.length() == 1);
1227 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001228 Map* old_map = object->map();
1229 if (!old_map->is_access_check_needed()) {
1230 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001231 Object* new_map;
1232 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1233 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1234 }
ager@chromium.org32912102009-01-16 10:38:43 +00001235
1236 Map::cast(new_map)->set_is_access_check_needed(true);
1237 object->set_map(Map::cast(new_map));
1238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001239 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001240}
1241
1242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001243static Failure* ThrowRedeclarationError(Isolate* isolate,
1244 const char* type,
1245 Handle<String> name) {
1246 HandleScope scope(isolate);
1247 Handle<Object> type_handle =
1248 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 Handle<Object> args[2] = { type_handle, name };
1250 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001251 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1252 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253}
1254
1255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001256RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001257 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001258 HandleScope scope(isolate);
1259 Handle<GlobalObject> global = Handle<GlobalObject>(
1260 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
ager@chromium.org3811b432009-10-28 14:53:37 +00001262 Handle<Context> context = args.at<Context>(0);
1263 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001264 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 // Traverse the name/value pairs and set the properties.
1267 int length = pairs->length();
1268 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001271 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272
1273 // We have to declare a global const property. To capture we only
1274 // assign to it when evaluating the assignment for "const x =
1275 // <expr>" the initial value is the hole.
1276 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001277 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 if (value->IsUndefined() || is_const_property) {
1279 // Lookup the property in the global object, and don't set the
1280 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001281 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 global->Lookup(*name, &lookup);
1283 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001284 // We found an existing property. Unless it was an interceptor
1285 // that claims the property is absent, skip this declaration.
1286 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 continue;
1288 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001289 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1290 if (attributes != ABSENT) {
1291 continue;
1292 }
1293 // Fall-through and introduce the absent property by using
1294 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 }
1296 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001297 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001299 Handle<SharedFunctionInfo> shared =
1300 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1303 context,
1304 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 value = function;
1306 }
1307
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001308 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 global->LocalLookup(*name, &lookup);
1310
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001311 // Compute the property attributes. According to ECMA-262, section
1312 // 13, page 71, the property must be read-only and
1313 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1314 // property as read-only, so we don't either.
1315 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001316 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001317 attr |= DONT_DELETE;
1318 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001319 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001320 if (is_const_property || (is_native && is_function_declaration)) {
1321 attr |= READ_ONLY;
1322 }
1323
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001324 // Safari does not allow the invocation of callback setters for
1325 // function declarations. To mimic this behavior, we do not allow
1326 // the invocation of setters for function values. This makes a
1327 // difference for global functions with the same names as event
1328 // handlers such as "function onload() {}". Firefox does call the
1329 // onload setter in those case and Safari does not. We follow
1330 // Safari for compatibility.
1331 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001332 // Do not change DONT_DELETE to false from true.
1333 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001334 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001335 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1337
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001338 RETURN_IF_EMPTY_HANDLE(isolate,
1339 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 name,
1341 value,
1342 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001344 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1345 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1346 ? kNonStrictMode : kStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001347 RETURN_IF_EMPTY_HANDLE(isolate,
1348 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001349 name,
1350 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001351 static_cast<PropertyAttributes>(attr),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001352 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 }
1354 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 ASSERT(!isolate->has_pending_exception());
1357 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358}
1359
1360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001361RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001363 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 // Declarations are always made in a function or global context. In the
1366 // case of eval code, the context passed is the context of the caller,
1367 // which may be some nested context and not the declaration context.
1368 RUNTIME_ASSERT(args[0]->IsContext());
1369 Handle<Context> context(Context::cast(args[0])->declaration_context());
1370
ager@chromium.org7c537e22008-10-16 08:43:32 +00001371 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001372 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001373 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 int index;
1377 PropertyAttributes attributes;
1378 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001379 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001380 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001381 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382
1383 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1386 // Functions are not read-only.
1387 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1388 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001389 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 }
1391
1392 // Initialize it if necessary.
1393 if (*initial_value != NULL) {
1394 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395 ASSERT(holder.is_identical_to(context));
1396 if (((attributes & READ_ONLY) == 0) ||
1397 context->get(index)->IsTheHole()) {
1398 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 // Slow case: The property is in the context extension object of a
1402 // function context or the global object of a global context.
1403 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001404 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001406 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 }
1408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001411 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001412 // "declared" in the function context's extension context or as a
1413 // property of the the global object.
1414 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001415 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001416 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001417 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 // Context extension objects are allocated lazily.
1419 ASSERT(context->IsFunctionContext());
1420 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001422 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001423 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 // Declare the property by setting it to the initial value if provided,
1427 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1428 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001430 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001431 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001432 // Declaring a const context slot is a conflicting declaration if
1433 // there is a callback with that name in a prototype. It is
1434 // allowed to introduce const variables in
1435 // JSContextExtensionObjects. They are treated specially in
1436 // SetProperty and no setters are invoked for those since they are
1437 // not real JSObjects.
1438 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001440 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001441 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001442 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001444 }
1445 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001448 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001449 }
1450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452}
1453
1454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001455RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001457 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001458 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001459 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // Determine if we need to assign to the variable if it already
1462 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1464 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465
1466 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001468 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001469 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1470 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1471 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472
1473 // According to ECMA-262, section 12.2, page 62, the property must
1474 // not be deletable.
1475 PropertyAttributes attributes = DONT_DELETE;
1476
1477 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001478 // there, there is a property with this name in the prototype chain.
1479 // We follow Safari and Firefox behavior and only set the property
1480 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001481 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001482 // Note that objects can have hidden prototypes, so we need to traverse
1483 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001484 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001485 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001486 while (object->IsJSObject() &&
1487 JSObject::cast(object)->map()->is_hidden_prototype()) {
1488 JSObject* raw_holder = JSObject::cast(object);
1489 raw_holder->LocalLookup(*name, &lookup);
1490 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1491 HandleScope handle_scope(isolate);
1492 Handle<JSObject> holder(raw_holder);
1493 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1494 // Update the raw pointer in case it's changed due to GC.
1495 raw_holder = *holder;
1496 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1497 // Found an interceptor that's not read only.
1498 if (assign) {
1499 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001500 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 } else {
1502 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001503 }
1504 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001505 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 }
1508
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001509 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001510 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001511 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001512 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001513 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001514 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515}
1516
1517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001518RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 // All constants are declared with an initial value. The name
1520 // of the constant is the first argument and the initial value
1521 // is the second.
1522 RUNTIME_ASSERT(args.length() == 2);
1523 CONVERT_ARG_CHECKED(String, name, 0);
1524 Handle<Object> value = args.at<Object>(1);
1525
1526 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528
1529 // According to ECMA-262, section 12.2, page 62, the property must
1530 // not be deletable. Since it's a const, it must be READ_ONLY too.
1531 PropertyAttributes attributes =
1532 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1533
1534 // Lookup the property locally in the global object. If it isn't
1535 // there, we add the property and take special precautions to always
1536 // add it as a local property even in case of callbacks in the
1537 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001538 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001539 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 global->LocalLookup(*name, &lookup);
1541 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001542 return global->SetLocalPropertyIgnoreAttributes(*name,
1543 *value,
1544 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 }
1546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001549 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001550 HandleScope handle_scope(isolate);
1551 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001553 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 // property through an interceptor and only do it if it's
1555 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001556 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 RETURN_IF_EMPTY_HANDLE(isolate,
1558 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001559 name,
1560 value,
1561 attributes,
1562 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 return *value;
1564 }
1565
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567 // constant. For now, we determine this by checking if the
1568 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 PropertyType type = lookup.type();
1571 if (type == FIELD) {
1572 FixedArray* properties = global->properties();
1573 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 properties->set(index, *value);
1576 }
1577 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001578 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1579 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001580 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 }
1582 } else {
1583 // Ignore re-initialization of constants that have already been
1584 // assigned a function value.
1585 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1586 }
1587
1588 // Use the set value as the result of the operation.
1589 return *value;
1590}
1591
1592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001593RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 ASSERT(args.length() == 3);
1596
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001599
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001600 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001601 RUNTIME_ASSERT(args[1]->IsContext());
1602 Handle<Context> context(Context::cast(args[1])->declaration_context());
1603
1604 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
1606 int index;
1607 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001608 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001609 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001610 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001611 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 ASSERT(holder->IsContext());
1615 // Property was found in a context. Perform the assignment if we
1616 // found some non-constant or an uninitialized constant.
1617 Handle<Context> context = Handle<Context>::cast(holder);
1618 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1619 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 }
1621 return *value;
1622 }
1623
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001624 // The property could not be found, we introduce it as a property of the
1625 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001627 Handle<JSObject> global = Handle<JSObject>(
1628 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001629 // Strict mode not needed (const disallowed in strict mode).
1630 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001632 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 return *value;
1634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 // The property was present in some function's context extension object,
1637 // as a property on the subject of a with, or as a property of the global
1638 // object.
1639 //
1640 // In most situations, eval-introduced consts should still be present in
1641 // the context extension object. However, because declaration and
1642 // initialization are separate, the property might have been deleted
1643 // before we reach the initialization point.
1644 //
1645 // Example:
1646 //
1647 // function f() { eval("delete x; const x;"); }
1648 //
1649 // In that case, the initialization behaves like a normal assignment.
1650 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001652 if (*object == context->extension()) {
1653 // This is the property that was introduced by the const declaration.
1654 // Set it if it hasn't been set before. NOTE: We cannot use
1655 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001656 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001657 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001658 ASSERT(lookup.IsProperty()); // the property was declared
1659 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1660
1661 PropertyType type = lookup.type();
1662 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001663 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 int index = lookup.GetFieldIndex();
1665 if (properties->get(index)->IsTheHole()) {
1666 properties->set(index, *value);
1667 }
1668 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001669 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1670 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001671 }
1672 } else {
1673 // We should not reach here. Any real, named property should be
1674 // either a field or a dictionary slot.
1675 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676 }
1677 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001678 // The property was found on some other object. Set it if it is not a
1679 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001680 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001681 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001682 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001683 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001684 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001685 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001686 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688 return *value;
1689}
1690
1691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001692RUNTIME_FUNCTION(MaybeObject*,
1693 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001694 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001695 ASSERT(args.length() == 2);
1696 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001697 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001698 if (object->HasFastProperties()) {
1699 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1700 }
1701 return *object;
1702}
1703
1704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001705RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001707 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001708 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1709 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001710 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001711 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001712 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001713 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001714 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001715 RUNTIME_ASSERT(index >= 0);
1716 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001718 Handle<Object> result = RegExpImpl::Exec(regexp,
1719 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001720 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001722 if (result.is_null()) return Failure::Exception();
1723 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724}
1725
1726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001727RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001728 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001729 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001730 if (elements_count < 0 ||
1731 elements_count > FixedArray::kMaxLength ||
1732 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001733 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001735 Object* new_object;
1736 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001738 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1739 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001740 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1742 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1744 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001745 {
1746 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001750 }
1751 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001753 array->set_elements(elements);
1754 array->set_length(Smi::FromInt(elements_count));
1755 // Write in-object properties after the length of the array.
1756 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1757 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1758 return array;
1759}
1760
1761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001762RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001763 AssertNoAllocation no_alloc;
1764 ASSERT(args.length() == 5);
1765 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1766 CONVERT_CHECKED(String, source, args[1]);
1767
1768 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770
1771 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001773
1774 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001776
1777 Map* map = regexp->map();
1778 Object* constructor = map->constructor();
1779 if (constructor->IsJSFunction() &&
1780 JSFunction::cast(constructor)->initial_map() == map) {
1781 // If we still have the original map, set in-object properties directly.
1782 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001783 // Both true and false are immovable immortal objects so no need for write
1784 // barrier.
1785 regexp->InObjectPropertyAtPut(
1786 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1787 regexp->InObjectPropertyAtPut(
1788 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1789 regexp->InObjectPropertyAtPut(
1790 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001791 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1792 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001793 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001794 return regexp;
1795 }
1796
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001797 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001798 PropertyAttributes final =
1799 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1800 PropertyAttributes writable =
1801 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001803 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001805 source,
1806 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001807 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001809 global,
1810 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001811 ASSERT(!result->IsFailure());
1812 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001814 ignoreCase,
1815 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001816 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001818 multiline,
1819 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001820 ASSERT(!result->IsFailure());
1821 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 Smi::FromInt(0),
1824 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
1826 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001827 return regexp;
1828}
1829
1830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001831RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001833 ASSERT(args.length() == 1);
1834 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1835 // This is necessary to enable fast checks for absence of elements
1836 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001837 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001838 return Smi::FromInt(0);
1839}
1840
1841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001842static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1843 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001844 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001845 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1847 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1848 Handle<JSFunction> optimized =
1849 isolate->factory()->NewFunction(key,
1850 JS_OBJECT_TYPE,
1851 JSObject::kHeaderSize,
1852 code,
1853 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001854 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001855 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856 return optimized;
1857}
1858
1859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001860RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001862 ASSERT(args.length() == 1);
1863 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1864
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001865 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1866 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1867 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1868 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1869 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1870 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1871 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001872
1873 return *holder;
1874}
1875
1876
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1878 NoHandleAllocation handle_free;
1879 ASSERT(args.length() == 1);
1880 CONVERT_CHECKED(JSFunction, function, args[0]);
1881 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001882 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001883 return isolate->heap()->undefined_value();
1884 }
1885 // Returns undefined for strict or native functions, or
1886 // the associated global receiver for "normal" functions.
1887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001888 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001889 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001890 return global_context->global()->global_receiver();
1891}
1892
1893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001894RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001895 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 ASSERT(args.length() == 4);
1897 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001898 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899 Handle<String> pattern = args.at<String>(2);
1900 Handle<String> flags = args.at<String>(3);
1901
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001902 // Get the RegExp function from the context in the literals array.
1903 // This is the RegExp function from the context in which the
1904 // function was created. We do not use the RegExp function from the
1905 // current global context because this might be the RegExp function
1906 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001908 Handle<JSFunction>(
1909 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 // Compute the regular expression literal.
1911 bool has_pending_exception;
1912 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001913 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1914 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001916 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001917 return Failure::Exception();
1918 }
1919 literals->set(index, *regexp);
1920 return *regexp;
1921}
1922
1923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001924RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 1);
1927
1928 CONVERT_CHECKED(JSFunction, f, args[0]);
1929 return f->shared()->name();
1930}
1931
1932
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001933RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001934 NoHandleAllocation ha;
1935 ASSERT(args.length() == 2);
1936
1937 CONVERT_CHECKED(JSFunction, f, args[0]);
1938 CONVERT_CHECKED(String, name, args[1]);
1939 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001941}
1942
1943
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001944RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1945 NoHandleAllocation ha;
1946 ASSERT(args.length() == 1);
1947 CONVERT_CHECKED(JSFunction, f, args[0]);
1948 return isolate->heap()->ToBoolean(
1949 f->shared()->name_should_print_as_anonymous());
1950}
1951
1952
1953RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1954 NoHandleAllocation ha;
1955 ASSERT(args.length() == 1);
1956 CONVERT_CHECKED(JSFunction, f, args[0]);
1957 f->shared()->set_name_should_print_as_anonymous(true);
1958 return isolate->heap()->undefined_value();
1959}
1960
1961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001962RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001963 NoHandleAllocation ha;
1964 ASSERT(args.length() == 1);
1965
1966 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001967 Object* obj = f->RemovePrototype();
1968 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001971}
1972
1973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001974RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 ASSERT(args.length() == 1);
1977
1978 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1980 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981
1982 return *GetScriptWrapper(Handle<Script>::cast(script));
1983}
1984
1985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
1989
1990 CONVERT_CHECKED(JSFunction, f, args[0]);
1991 return f->shared()->GetSourceCode();
1992}
1993
1994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001995RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
1999 CONVERT_CHECKED(JSFunction, fun, args[0]);
2000 int pos = fun->shared()->start_position();
2001 return Smi::FromInt(pos);
2002}
2003
2004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002005RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002006 ASSERT(args.length() == 2);
2007
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002009 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2010
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002011 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2012
2013 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002014 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002015}
2016
2017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002018RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002019 NoHandleAllocation ha;
2020 ASSERT(args.length() == 2);
2021
2022 CONVERT_CHECKED(JSFunction, fun, args[0]);
2023 CONVERT_CHECKED(String, name, args[1]);
2024 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002025 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 2);
2032
2033 CONVERT_CHECKED(JSFunction, fun, args[0]);
2034 CONVERT_CHECKED(Smi, length, args[1]);
2035 fun->shared()->set_length(length->value());
2036 return length;
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002041 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 ASSERT(args.length() == 2);
2043
2044 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002045 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002046 Object* obj;
2047 { MaybeObject* maybe_obj =
2048 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2049 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051 return args[0]; // return TOS
2052}
2053
2054
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002055RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2056 NoHandleAllocation ha;
2057 RUNTIME_ASSERT(args.length() == 1);
2058 CONVERT_CHECKED(JSFunction, function, args[0]);
2059
2060 MaybeObject* maybe_name =
2061 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2062 String* name;
2063 if (!maybe_name->To(&name)) return maybe_name;
2064
2065 if (function->HasFastProperties()) {
2066 // Construct a new field descriptor with updated attributes.
2067 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2068 int index = instance_desc->Search(name);
2069 ASSERT(index != DescriptorArray::kNotFound);
2070 PropertyDetails details(instance_desc->GetDetails(index));
2071 CallbacksDescriptor new_desc(name,
2072 instance_desc->GetValue(index),
2073 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2074 details.index());
2075 // Construct a new field descriptors array containing the new descriptor.
2076 Object* descriptors_unchecked;
2077 { MaybeObject* maybe_descriptors_unchecked =
2078 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2079 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2080 return maybe_descriptors_unchecked;
2081 }
2082 }
2083 DescriptorArray* new_descriptors =
2084 DescriptorArray::cast(descriptors_unchecked);
2085 // Create a new map featuring the new field descriptors array.
2086 Object* map_unchecked;
2087 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2088 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2089 return maybe_map_unchecked;
2090 }
2091 }
2092 Map* new_map = Map::cast(map_unchecked);
2093 new_map->set_instance_descriptors(new_descriptors);
2094 function->set_map(new_map);
2095 } else { // Dictionary properties.
2096 // Directly manipulate the property details.
2097 int entry = function->property_dictionary()->FindEntry(name);
2098 ASSERT(entry != StringDictionary::kNotFound);
2099 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2100 PropertyDetails new_details(
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.type(),
2103 details.index());
2104 function->property_dictionary()->DetailsAtPut(entry, new_details);
2105 }
2106 return function;
2107}
2108
2109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002110RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002111 NoHandleAllocation ha;
2112 ASSERT(args.length() == 1);
2113
2114 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002115 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002116}
2117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002119RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 1);
2122
2123 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002124 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002125}
2126
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002128RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002130 ASSERT(args.length() == 2);
2131
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002132 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002133 Handle<Object> code = args.at<Object>(1);
2134
2135 Handle<Context> context(target->context());
2136
2137 if (!code->IsNull()) {
2138 RUNTIME_ASSERT(code->IsJSFunction());
2139 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002141
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002142 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002143 return Failure::Exception();
2144 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 // Since we don't store the source for this we should never
2146 // optimize this.
2147 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002148 // Set the code, scope info, formal parameter count,
2149 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002150 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002151 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002152 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002153 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002155 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002156 // Set the source code of the target function to undefined.
2157 // SetCode is only used for built-in constructors like String,
2158 // Array, and Object, and some web code
2159 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002160 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002161 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002162 // Clear the optimization hints related to the compiled code as these are no
2163 // longer valid when the code is overwritten.
2164 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002165 context = Handle<Context>(fun->context());
2166
2167 // Make sure we get a fresh copy of the literal vector to avoid
2168 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002169 int number_of_literals = fun->NumberOfLiterals();
2170 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002171 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002173 // Insert the object, regexp and array functions in the literals
2174 // array prefix. These are the functions that will be used when
2175 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002176 literals->set(JSFunction::kLiteralGlobalContextIndex,
2177 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002179 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002180 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002181
2182 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2183 isolate->logger()->LogExistingFunction(
2184 shared, Handle<Code>(shared->code()));
2185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186 }
2187
2188 target->set_context(*context);
2189 return *target;
2190}
2191
2192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002193RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002195 ASSERT(args.length() == 2);
2196 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002197 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002198 RUNTIME_ASSERT(num >= 0);
2199 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002200 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002201}
2202
2203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002204MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2205 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002206 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002207 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002208 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002209 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002210 }
2211 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002213}
2214
2215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002216RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217 NoHandleAllocation ha;
2218 ASSERT(args.length() == 2);
2219
2220 CONVERT_CHECKED(String, subject, args[0]);
2221 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002223
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002224 uint32_t i = 0;
2225 if (index->IsSmi()) {
2226 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002228 i = value;
2229 } else {
2230 ASSERT(index->IsHeapNumber());
2231 double value = HeapNumber::cast(index)->value();
2232 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002233 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002234
2235 // Flatten the string. If someone wants to get a char at an index
2236 // in a cons string, it is likely that more indices will be
2237 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002238 Object* flat;
2239 { MaybeObject* maybe_flat = subject->TryFlatten();
2240 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2241 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002242 subject = String::cast(flat);
2243
2244 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002245 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002246 }
2247
2248 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002249}
2250
2251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002252RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253 NoHandleAllocation ha;
2254 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002255 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002256}
2257
lrn@chromium.org25156de2010-04-06 13:10:27 +00002258
2259class FixedArrayBuilder {
2260 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2262 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002263 length_(0),
2264 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002265 // Require a non-zero initial size. Ensures that doubling the size to
2266 // extend the array will work.
2267 ASSERT(initial_capacity > 0);
2268 }
2269
2270 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2271 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002272 length_(0),
2273 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002274 // Require a non-zero initial size. Ensures that doubling the size to
2275 // extend the array will work.
2276 ASSERT(backing_store->length() > 0);
2277 }
2278
2279 bool HasCapacity(int elements) {
2280 int length = array_->length();
2281 int required_length = length_ + elements;
2282 return (length >= required_length);
2283 }
2284
2285 void EnsureCapacity(int elements) {
2286 int length = array_->length();
2287 int required_length = length_ + elements;
2288 if (length < required_length) {
2289 int new_length = length;
2290 do {
2291 new_length *= 2;
2292 } while (new_length < required_length);
2293 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002294 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 array_->CopyTo(0, *extended_array, 0, length_);
2296 array_ = extended_array;
2297 }
2298 }
2299
2300 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002301 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 ASSERT(length_ < capacity());
2303 array_->set(length_, value);
2304 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002305 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 }
2307
2308 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002309 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002310 ASSERT(length_ < capacity());
2311 array_->set(length_, value);
2312 length_++;
2313 }
2314
2315 Handle<FixedArray> array() {
2316 return array_;
2317 }
2318
2319 int length() {
2320 return length_;
2321 }
2322
2323 int capacity() {
2324 return array_->length();
2325 }
2326
2327 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 result_array->set_length(Smi::FromInt(length_));
2330 return result_array;
2331 }
2332
2333 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002334 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002335 target_array->set_length(Smi::FromInt(length_));
2336 return target_array;
2337 }
2338
2339 private:
2340 Handle<FixedArray> array_;
2341 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002342 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002343};
2344
2345
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002346// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002347const int kStringBuilderConcatHelperLengthBits = 11;
2348const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002349
2350template <typename schar>
2351static inline void StringBuilderConcatHelper(String*,
2352 schar*,
2353 FixedArray*,
2354 int);
2355
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2357 StringBuilderSubstringLength;
2358typedef BitField<int,
2359 kStringBuilderConcatHelperLengthBits,
2360 kStringBuilderConcatHelperPositionBits>
2361 StringBuilderSubstringPosition;
2362
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363
2364class ReplacementStringBuilder {
2365 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002366 ReplacementStringBuilder(Heap* heap,
2367 Handle<String> subject,
2368 int estimated_part_count)
2369 : heap_(heap),
2370 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002371 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002372 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002373 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374 // Require a non-zero initial size. Ensures that doubling the size to
2375 // extend the array will work.
2376 ASSERT(estimated_part_count > 0);
2377 }
2378
lrn@chromium.org25156de2010-04-06 13:10:27 +00002379 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2380 int from,
2381 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002382 ASSERT(from >= 0);
2383 int length = to - from;
2384 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385 if (StringBuilderSubstringLength::is_valid(length) &&
2386 StringBuilderSubstringPosition::is_valid(from)) {
2387 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2388 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002390 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002391 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392 builder->Add(Smi::FromInt(-length));
2393 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002394 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002395 }
2396
2397
2398 void EnsureCapacity(int elements) {
2399 array_builder_.EnsureCapacity(elements);
2400 }
2401
2402
2403 void AddSubjectSlice(int from, int to) {
2404 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002405 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 }
2407
2408
2409 void AddString(Handle<String> string) {
2410 int length = string->length();
2411 ASSERT(length > 0);
2412 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002413 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002414 is_ascii_ = false;
2415 }
2416 IncrementCharacterCount(length);
2417 }
2418
2419
2420 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002421 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002422 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 }
2424
2425 Handle<String> joined_string;
2426 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002427 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002429 char* char_buffer = seq->GetChars();
2430 StringBuilderConcatHelper(*subject_,
2431 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002432 *array_builder_.array(),
2433 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002434 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 } else {
2436 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002437 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002438 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 uc16* char_buffer = seq->GetChars();
2440 StringBuilderConcatHelper(*subject_,
2441 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002442 *array_builder_.array(),
2443 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002444 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002445 }
2446 return joined_string;
2447 }
2448
2449
2450 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002451 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002452 V8::FatalProcessOutOfMemory("String.replace result too large.");
2453 }
2454 character_count_ += by;
2455 }
2456
lrn@chromium.org25156de2010-04-06 13:10:27 +00002457 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002458 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002460
lrn@chromium.org25156de2010-04-06 13:10:27 +00002461 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2463 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 }
2465
2466
ager@chromium.org04921a82011-06-27 13:21:41 +00002467 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2468 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 }
2470
2471
2472 void AddElement(Object* element) {
2473 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002474 ASSERT(array_builder_.capacity() > array_builder_.length());
2475 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002476 }
2477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002478 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002479 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 int character_count_;
2482 bool is_ascii_;
2483};
2484
2485
2486class CompiledReplacement {
2487 public:
2488 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002489 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490
2491 void Compile(Handle<String> replacement,
2492 int capture_count,
2493 int subject_length);
2494
2495 void Apply(ReplacementStringBuilder* builder,
2496 int match_from,
2497 int match_to,
2498 Handle<JSArray> last_match_info);
2499
2500 // Number of distinct parts of the replacement pattern.
2501 int parts() {
2502 return parts_.length();
2503 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002504
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002505 bool simple_hint() {
2506 return simple_hint_;
2507 }
2508
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002509 private:
2510 enum PartType {
2511 SUBJECT_PREFIX = 1,
2512 SUBJECT_SUFFIX,
2513 SUBJECT_CAPTURE,
2514 REPLACEMENT_SUBSTRING,
2515 REPLACEMENT_STRING,
2516
2517 NUMBER_OF_PART_TYPES
2518 };
2519
2520 struct ReplacementPart {
2521 static inline ReplacementPart SubjectMatch() {
2522 return ReplacementPart(SUBJECT_CAPTURE, 0);
2523 }
2524 static inline ReplacementPart SubjectCapture(int capture_index) {
2525 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2526 }
2527 static inline ReplacementPart SubjectPrefix() {
2528 return ReplacementPart(SUBJECT_PREFIX, 0);
2529 }
2530 static inline ReplacementPart SubjectSuffix(int subject_length) {
2531 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2532 }
2533 static inline ReplacementPart ReplacementString() {
2534 return ReplacementPart(REPLACEMENT_STRING, 0);
2535 }
2536 static inline ReplacementPart ReplacementSubString(int from, int to) {
2537 ASSERT(from >= 0);
2538 ASSERT(to > from);
2539 return ReplacementPart(-from, to);
2540 }
2541
2542 // If tag <= 0 then it is the negation of a start index of a substring of
2543 // the replacement pattern, otherwise it's a value from PartType.
2544 ReplacementPart(int tag, int data)
2545 : tag(tag), data(data) {
2546 // Must be non-positive or a PartType value.
2547 ASSERT(tag < NUMBER_OF_PART_TYPES);
2548 }
2549 // Either a value of PartType or a non-positive number that is
2550 // the negation of an index into the replacement string.
2551 int tag;
2552 // The data value's interpretation depends on the value of tag:
2553 // tag == SUBJECT_PREFIX ||
2554 // tag == SUBJECT_SUFFIX: data is unused.
2555 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2556 // tag == REPLACEMENT_SUBSTRING ||
2557 // tag == REPLACEMENT_STRING: data is index into array of substrings
2558 // of the replacement string.
2559 // tag <= 0: Temporary representation of the substring of the replacement
2560 // string ranging over -tag .. data.
2561 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2562 // substring objects.
2563 int data;
2564 };
2565
2566 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002567 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 Vector<Char> characters,
2569 int capture_count,
2570 int subject_length) {
2571 int length = characters.length();
2572 int last = 0;
2573 for (int i = 0; i < length; i++) {
2574 Char c = characters[i];
2575 if (c == '$') {
2576 int next_index = i + 1;
2577 if (next_index == length) { // No next character!
2578 break;
2579 }
2580 Char c2 = characters[next_index];
2581 switch (c2) {
2582 case '$':
2583 if (i > last) {
2584 // There is a substring before. Include the first "$".
2585 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2586 last = next_index + 1; // Continue after the second "$".
2587 } else {
2588 // Let the next substring start with the second "$".
2589 last = next_index;
2590 }
2591 i = next_index;
2592 break;
2593 case '`':
2594 if (i > last) {
2595 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2596 }
2597 parts->Add(ReplacementPart::SubjectPrefix());
2598 i = next_index;
2599 last = i + 1;
2600 break;
2601 case '\'':
2602 if (i > last) {
2603 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2604 }
2605 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2606 i = next_index;
2607 last = i + 1;
2608 break;
2609 case '&':
2610 if (i > last) {
2611 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2612 }
2613 parts->Add(ReplacementPart::SubjectMatch());
2614 i = next_index;
2615 last = i + 1;
2616 break;
2617 case '0':
2618 case '1':
2619 case '2':
2620 case '3':
2621 case '4':
2622 case '5':
2623 case '6':
2624 case '7':
2625 case '8':
2626 case '9': {
2627 int capture_ref = c2 - '0';
2628 if (capture_ref > capture_count) {
2629 i = next_index;
2630 continue;
2631 }
2632 int second_digit_index = next_index + 1;
2633 if (second_digit_index < length) {
2634 // Peek ahead to see if we have two digits.
2635 Char c3 = characters[second_digit_index];
2636 if ('0' <= c3 && c3 <= '9') { // Double digits.
2637 int double_digit_ref = capture_ref * 10 + c3 - '0';
2638 if (double_digit_ref <= capture_count) {
2639 next_index = second_digit_index;
2640 capture_ref = double_digit_ref;
2641 }
2642 }
2643 }
2644 if (capture_ref > 0) {
2645 if (i > last) {
2646 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2647 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002648 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002649 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2650 last = next_index + 1;
2651 }
2652 i = next_index;
2653 break;
2654 }
2655 default:
2656 i = next_index;
2657 break;
2658 }
2659 }
2660 }
2661 if (length > last) {
2662 if (last == 0) {
2663 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002664 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665 } else {
2666 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2667 }
2668 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002669 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670 }
2671
2672 ZoneList<ReplacementPart> parts_;
2673 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002674 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002675};
2676
2677
2678void CompiledReplacement::Compile(Handle<String> replacement,
2679 int capture_count,
2680 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002681 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002682 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002683 String::FlatContent content = replacement->GetFlatContent();
2684 ASSERT(content.IsFlat());
2685 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002686 simple_hint_ = ParseReplacementPattern(&parts_,
2687 content.ToAsciiVector(),
2688 capture_count,
2689 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002690 } else {
2691 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002692 simple_hint_ = ParseReplacementPattern(&parts_,
2693 content.ToUC16Vector(),
2694 capture_count,
2695 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002696 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002697 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002698 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002699 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700 int substring_index = 0;
2701 for (int i = 0, n = parts_.length(); i < n; i++) {
2702 int tag = parts_[i].tag;
2703 if (tag <= 0) { // A replacement string slice.
2704 int from = -tag;
2705 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 replacement_substrings_.Add(
2707 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002708 parts_[i].tag = REPLACEMENT_SUBSTRING;
2709 parts_[i].data = substring_index;
2710 substring_index++;
2711 } else if (tag == REPLACEMENT_STRING) {
2712 replacement_substrings_.Add(replacement);
2713 parts_[i].data = substring_index;
2714 substring_index++;
2715 }
2716 }
2717}
2718
2719
2720void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2721 int match_from,
2722 int match_to,
2723 Handle<JSArray> last_match_info) {
2724 for (int i = 0, n = parts_.length(); i < n; i++) {
2725 ReplacementPart part = parts_[i];
2726 switch (part.tag) {
2727 case SUBJECT_PREFIX:
2728 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2729 break;
2730 case SUBJECT_SUFFIX: {
2731 int subject_length = part.data;
2732 if (match_to < subject_length) {
2733 builder->AddSubjectSlice(match_to, subject_length);
2734 }
2735 break;
2736 }
2737 case SUBJECT_CAPTURE: {
2738 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002739 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002740 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2741 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2742 if (from >= 0 && to > from) {
2743 builder->AddSubjectSlice(from, to);
2744 }
2745 break;
2746 }
2747 case REPLACEMENT_SUBSTRING:
2748 case REPLACEMENT_STRING:
2749 builder->AddString(replacement_substrings_[part.data]);
2750 break;
2751 default:
2752 UNREACHABLE();
2753 }
2754 }
2755}
2756
2757
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002758void FindAsciiStringIndices(Vector<const char> subject,
2759 char pattern,
2760 ZoneList<int>* indices,
2761 unsigned int limit) {
2762 ASSERT(limit > 0);
2763 // Collect indices of pattern in subject using memchr.
2764 // Stop after finding at most limit values.
2765 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2766 const char* subject_end = subject_start + subject.length();
2767 const char* pos = subject_start;
2768 while (limit > 0) {
2769 pos = reinterpret_cast<const char*>(
2770 memchr(pos, pattern, subject_end - pos));
2771 if (pos == NULL) return;
2772 indices->Add(static_cast<int>(pos - subject_start));
2773 pos++;
2774 limit--;
2775 }
2776}
2777
2778
2779template <typename SubjectChar, typename PatternChar>
2780void FindStringIndices(Isolate* isolate,
2781 Vector<const SubjectChar> subject,
2782 Vector<const PatternChar> pattern,
2783 ZoneList<int>* indices,
2784 unsigned int limit) {
2785 ASSERT(limit > 0);
2786 // Collect indices of pattern in subject.
2787 // Stop after finding at most limit values.
2788 int pattern_length = pattern.length();
2789 int index = 0;
2790 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2791 while (limit > 0) {
2792 index = search.Search(subject, index);
2793 if (index < 0) return;
2794 indices->Add(index);
2795 index += pattern_length;
2796 limit--;
2797 }
2798}
2799
2800
2801void FindStringIndicesDispatch(Isolate* isolate,
2802 String* subject,
2803 String* pattern,
2804 ZoneList<int>* indices,
2805 unsigned int limit) {
2806 {
2807 AssertNoAllocation no_gc;
2808 String::FlatContent subject_content = subject->GetFlatContent();
2809 String::FlatContent pattern_content = pattern->GetFlatContent();
2810 ASSERT(subject_content.IsFlat());
2811 ASSERT(pattern_content.IsFlat());
2812 if (subject_content.IsAscii()) {
2813 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2814 if (pattern_content.IsAscii()) {
2815 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2816 if (pattern_vector.length() == 1) {
2817 FindAsciiStringIndices(subject_vector,
2818 pattern_vector[0],
2819 indices,
2820 limit);
2821 } else {
2822 FindStringIndices(isolate,
2823 subject_vector,
2824 pattern_vector,
2825 indices,
2826 limit);
2827 }
2828 } else {
2829 FindStringIndices(isolate,
2830 subject_vector,
2831 pattern_content.ToUC16Vector(),
2832 indices,
2833 limit);
2834 }
2835 } else {
2836 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002837 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002838 FindStringIndices(isolate,
2839 subject_vector,
2840 pattern_content.ToAsciiVector(),
2841 indices,
2842 limit);
2843 } else {
2844 FindStringIndices(isolate,
2845 subject_vector,
2846 pattern_content.ToUC16Vector(),
2847 indices,
2848 limit);
2849 }
2850 }
2851 }
2852}
2853
2854
2855template<typename ResultSeqString>
2856MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2857 Isolate* isolate,
2858 Handle<String> subject,
2859 Handle<JSRegExp> pattern_regexp,
2860 Handle<String> replacement) {
2861 ASSERT(subject->IsFlat());
2862 ASSERT(replacement->IsFlat());
2863
2864 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2865 ZoneList<int> indices(8);
2866 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2867 String* pattern =
2868 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2869 int subject_len = subject->length();
2870 int pattern_len = pattern->length();
2871 int replacement_len = replacement->length();
2872
2873 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2874
2875 int matches = indices.length();
2876 if (matches == 0) return *subject;
2877
2878 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2879 int subject_pos = 0;
2880 int result_pos = 0;
2881
2882 Handle<ResultSeqString> result;
2883 if (ResultSeqString::kHasAsciiEncoding) {
2884 result = Handle<ResultSeqString>::cast(
2885 isolate->factory()->NewRawAsciiString(result_len));
2886 } else {
2887 result = Handle<ResultSeqString>::cast(
2888 isolate->factory()->NewRawTwoByteString(result_len));
2889 }
2890
2891 for (int i = 0; i < matches; i++) {
2892 // Copy non-matched subject content.
2893 if (subject_pos < indices.at(i)) {
2894 String::WriteToFlat(*subject,
2895 result->GetChars() + result_pos,
2896 subject_pos,
2897 indices.at(i));
2898 result_pos += indices.at(i) - subject_pos;
2899 }
2900
2901 // Replace match.
2902 if (replacement_len > 0) {
2903 String::WriteToFlat(*replacement,
2904 result->GetChars() + result_pos,
2905 0,
2906 replacement_len);
2907 result_pos += replacement_len;
2908 }
2909
2910 subject_pos = indices.at(i) + pattern_len;
2911 }
2912 // Add remaining subject content at the end.
2913 if (subject_pos < subject_len) {
2914 String::WriteToFlat(*subject,
2915 result->GetChars() + result_pos,
2916 subject_pos,
2917 subject_len);
2918 }
2919 return *result;
2920}
2921
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002922
lrn@chromium.org303ada72010-10-27 09:33:13 +00002923MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002924 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002925 String* subject,
2926 JSRegExp* regexp,
2927 String* replacement,
2928 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002929 ASSERT(subject->IsFlat());
2930 ASSERT(replacement->IsFlat());
2931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002932 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002933
2934 int length = subject->length();
2935 Handle<String> subject_handle(subject);
2936 Handle<JSRegExp> regexp_handle(regexp);
2937 Handle<String> replacement_handle(replacement);
2938 Handle<JSArray> last_match_info_handle(last_match_info);
2939 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2940 subject_handle,
2941 0,
2942 last_match_info_handle);
2943 if (match.is_null()) {
2944 return Failure::Exception();
2945 }
2946 if (match->IsNull()) {
2947 return *subject_handle;
2948 }
2949
2950 int capture_count = regexp_handle->CaptureCount();
2951
2952 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002953 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954 CompiledReplacement compiled_replacement;
2955 compiled_replacement.Compile(replacement_handle,
2956 capture_count,
2957 length);
2958
2959 bool is_global = regexp_handle->GetFlags().is_global();
2960
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002961 // Shortcut for simple non-regexp global replacements
2962 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002963 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002964 compiled_replacement.simple_hint()) {
2965 if (subject_handle->HasOnlyAsciiChars() &&
2966 replacement_handle->HasOnlyAsciiChars()) {
2967 return StringReplaceStringWithString<SeqAsciiString>(
2968 isolate, subject_handle, regexp_handle, replacement_handle);
2969 } else {
2970 return StringReplaceStringWithString<SeqTwoByteString>(
2971 isolate, subject_handle, regexp_handle, replacement_handle);
2972 }
2973 }
2974
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002975 // Guessing the number of parts that the final result string is built
2976 // from. Global regexps can match any number of times, so we guess
2977 // conservatively.
2978 int expected_parts =
2979 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002980 ReplacementStringBuilder builder(isolate->heap(),
2981 subject_handle,
2982 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002983
2984 // Index of end of last match.
2985 int prev = 0;
2986
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002987 // Number of parts added by compiled replacement plus preceeding
2988 // string and possibly suffix after last match. It is possible for
2989 // all components to use two elements when encoded as two smis.
2990 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002991 bool matched = true;
2992 do {
2993 ASSERT(last_match_info_handle->HasFastElements());
2994 // Increase the capacity of the builder before entering local handle-scope,
2995 // so its internal buffer can safely allocate a new handle if it grows.
2996 builder.EnsureCapacity(parts_added_per_loop);
2997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002998 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002999 int start, end;
3000 {
3001 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003002 FixedArray* match_info_array =
3003 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004
3005 ASSERT_EQ(capture_count * 2 + 2,
3006 RegExpImpl::GetLastCaptureCount(match_info_array));
3007 start = RegExpImpl::GetCapture(match_info_array, 0);
3008 end = RegExpImpl::GetCapture(match_info_array, 1);
3009 }
3010
3011 if (prev < start) {
3012 builder.AddSubjectSlice(prev, start);
3013 }
3014 compiled_replacement.Apply(&builder,
3015 start,
3016 end,
3017 last_match_info_handle);
3018 prev = end;
3019
3020 // Only continue checking for global regexps.
3021 if (!is_global) break;
3022
3023 // Continue from where the match ended, unless it was an empty match.
3024 int next = end;
3025 if (start == end) {
3026 next = end + 1;
3027 if (next > length) break;
3028 }
3029
3030 match = RegExpImpl::Exec(regexp_handle,
3031 subject_handle,
3032 next,
3033 last_match_info_handle);
3034 if (match.is_null()) {
3035 return Failure::Exception();
3036 }
3037 matched = !match->IsNull();
3038 } while (matched);
3039
3040 if (prev < length) {
3041 builder.AddSubjectSlice(prev, length);
3042 }
3043
3044 return *(builder.ToString());
3045}
3046
3047
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003048template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003049MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003050 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003051 String* subject,
3052 JSRegExp* regexp,
3053 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003054 ASSERT(subject->IsFlat());
3055
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003056 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003057
3058 Handle<String> subject_handle(subject);
3059 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003060
3061 // Shortcut for simple non-regexp global replacements
3062 if (regexp_handle->GetFlags().is_global() &&
3063 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3064 Handle<String> empty_string_handle(HEAP->empty_string());
3065 if (subject_handle->HasOnlyAsciiChars()) {
3066 return StringReplaceStringWithString<SeqAsciiString>(
3067 isolate, subject_handle, regexp_handle, empty_string_handle);
3068 } else {
3069 return StringReplaceStringWithString<SeqTwoByteString>(
3070 isolate, subject_handle, regexp_handle, empty_string_handle);
3071 }
3072 }
3073
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003074 Handle<JSArray> last_match_info_handle(last_match_info);
3075 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3076 subject_handle,
3077 0,
3078 last_match_info_handle);
3079 if (match.is_null()) return Failure::Exception();
3080 if (match->IsNull()) return *subject_handle;
3081
3082 ASSERT(last_match_info_handle->HasFastElements());
3083
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003084 int start, end;
3085 {
3086 AssertNoAllocation match_info_array_is_not_in_a_handle;
3087 FixedArray* match_info_array =
3088 FixedArray::cast(last_match_info_handle->elements());
3089
3090 start = RegExpImpl::GetCapture(match_info_array, 0);
3091 end = RegExpImpl::GetCapture(match_info_array, 1);
3092 }
3093
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003094 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003095 int new_length = length - (end - start);
3096 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003097 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003098 }
3099 Handle<ResultSeqString> answer;
3100 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 answer = Handle<ResultSeqString>::cast(
3102 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003103 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003104 answer = Handle<ResultSeqString>::cast(
3105 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003106 }
3107
3108 // If the regexp isn't global, only match once.
3109 if (!regexp_handle->GetFlags().is_global()) {
3110 if (start > 0) {
3111 String::WriteToFlat(*subject_handle,
3112 answer->GetChars(),
3113 0,
3114 start);
3115 }
3116 if (end < length) {
3117 String::WriteToFlat(*subject_handle,
3118 answer->GetChars() + start,
3119 end,
3120 length);
3121 }
3122 return *answer;
3123 }
3124
3125 int prev = 0; // Index of end of last match.
3126 int next = 0; // Start of next search (prev unless last match was empty).
3127 int position = 0;
3128
3129 do {
3130 if (prev < start) {
3131 // Add substring subject[prev;start] to answer string.
3132 String::WriteToFlat(*subject_handle,
3133 answer->GetChars() + position,
3134 prev,
3135 start);
3136 position += start - prev;
3137 }
3138 prev = end;
3139 next = end;
3140 // Continue from where the match ended, unless it was an empty match.
3141 if (start == end) {
3142 next++;
3143 if (next > length) break;
3144 }
3145 match = RegExpImpl::Exec(regexp_handle,
3146 subject_handle,
3147 next,
3148 last_match_info_handle);
3149 if (match.is_null()) return Failure::Exception();
3150 if (match->IsNull()) break;
3151
3152 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003153 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003154 {
3155 AssertNoAllocation match_info_array_is_not_in_a_handle;
3156 FixedArray* match_info_array =
3157 FixedArray::cast(last_match_info_handle->elements());
3158 start = RegExpImpl::GetCapture(match_info_array, 0);
3159 end = RegExpImpl::GetCapture(match_info_array, 1);
3160 }
3161 } while (true);
3162
3163 if (prev < length) {
3164 // Add substring subject[prev;length] to answer string.
3165 String::WriteToFlat(*subject_handle,
3166 answer->GetChars() + position,
3167 prev,
3168 length);
3169 position += length - prev;
3170 }
3171
3172 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003174 }
3175
3176 // Shorten string and fill
3177 int string_size = ResultSeqString::SizeFor(position);
3178 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3179 int delta = allocated_string_size - string_size;
3180
3181 answer->set_length(position);
3182 if (delta == 0) return *answer;
3183
3184 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003185 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003186 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3187 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3188 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003189
3190 return *answer;
3191}
3192
3193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003194RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003195 ASSERT(args.length() == 4);
3196
3197 CONVERT_CHECKED(String, subject, args[0]);
3198 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003199 Object* flat_subject;
3200 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3201 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3202 return maybe_flat_subject;
3203 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003204 }
3205 subject = String::cast(flat_subject);
3206 }
3207
3208 CONVERT_CHECKED(String, replacement, args[2]);
3209 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003210 Object* flat_replacement;
3211 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3212 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3213 return maybe_flat_replacement;
3214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003215 }
3216 replacement = String::cast(flat_replacement);
3217 }
3218
3219 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3220 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3221
3222 ASSERT(last_match_info->HasFastElements());
3223
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003224 if (replacement->length() == 0) {
3225 if (subject->HasOnlyAsciiChars()) {
3226 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003227 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003228 } else {
3229 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003230 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003231 }
3232 }
3233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003234 return StringReplaceRegExpWithString(isolate,
3235 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003236 regexp,
3237 replacement,
3238 last_match_info);
3239}
3240
3241
ager@chromium.org7c537e22008-10-16 08:43:32 +00003242// Perform string match of pattern on subject, starting at start index.
3243// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003244// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245int Runtime::StringMatch(Isolate* isolate,
3246 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003247 Handle<String> pat,
3248 int start_index) {
3249 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003250 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003251
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003252 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003253 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003254
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003255 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003256 if (start_index + pattern_length > subject_length) return -1;
3257
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003258 if (!sub->IsFlat()) FlattenString(sub);
3259 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003260
ager@chromium.org7c537e22008-10-16 08:43:32 +00003261 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003262 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003263 String::FlatContent seq_sub = sub->GetFlatContent();
3264 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003265
ager@chromium.org7c537e22008-10-16 08:43:32 +00003266 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003267 if (seq_pat.IsAscii()) {
3268 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3269 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003270 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003271 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003272 pat_vector,
3273 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003274 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003275 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003276 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003277 pat_vector,
3278 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003279 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003280 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3281 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003282 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003283 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 pat_vector,
3285 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003286 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003287 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003288 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003289 pat_vector,
3290 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003291}
3292
3293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003294RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003295 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003296 ASSERT(args.length() == 3);
3297
ager@chromium.org7c537e22008-10-16 08:43:32 +00003298 CONVERT_ARG_CHECKED(String, sub, 0);
3299 CONVERT_ARG_CHECKED(String, pat, 1);
3300
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003301 Object* index = args[2];
3302 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003303 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003304
ager@chromium.org870a0b62008-11-04 11:43:05 +00003305 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003306 int position =
3307 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003308 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003309}
3310
3311
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003312template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003313static int StringMatchBackwards(Vector<const schar> subject,
3314 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003315 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003316 int pattern_length = pattern.length();
3317 ASSERT(pattern_length >= 1);
3318 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003319
3320 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003321 for (int i = 0; i < pattern_length; i++) {
3322 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003323 if (c > String::kMaxAsciiCharCode) {
3324 return -1;
3325 }
3326 }
3327 }
3328
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003329 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003330 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003331 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003332 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003333 while (j < pattern_length) {
3334 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003335 break;
3336 }
3337 j++;
3338 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003339 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003340 return i;
3341 }
3342 }
3343 return -1;
3344}
3345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003346RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003347 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 ASSERT(args.length() == 3);
3349
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003350 CONVERT_ARG_CHECKED(String, sub, 0);
3351 CONVERT_ARG_CHECKED(String, pat, 1);
3352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003355 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003356
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003357 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003358 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003360 if (start_index + pat_length > sub_length) {
3361 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003362 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003364 if (pat_length == 0) {
3365 return Smi::FromInt(start_index);
3366 }
3367
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003368 if (!sub->IsFlat()) FlattenString(sub);
3369 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003370
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003371 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003372 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3373
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 String::FlatContent sub_content = sub->GetFlatContent();
3375 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003376
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003377 if (pat_content.IsAscii()) {
3378 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3379 if (sub_content.IsAscii()) {
3380 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003381 pat_vector,
3382 start_index);
3383 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003384 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003385 pat_vector,
3386 start_index);
3387 }
3388 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003389 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3390 if (sub_content.IsAscii()) {
3391 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003392 pat_vector,
3393 start_index);
3394 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003396 pat_vector,
3397 start_index);
3398 }
3399 }
3400
3401 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402}
3403
3404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003405RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 NoHandleAllocation ha;
3407 ASSERT(args.length() == 2);
3408
3409 CONVERT_CHECKED(String, str1, args[0]);
3410 CONVERT_CHECKED(String, str2, args[1]);
3411
3412 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003413 int str1_length = str1->length();
3414 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415
3416 // Decide trivial cases without flattening.
3417 if (str1_length == 0) {
3418 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3419 return Smi::FromInt(-str2_length);
3420 } else {
3421 if (str2_length == 0) return Smi::FromInt(str1_length);
3422 }
3423
3424 int end = str1_length < str2_length ? str1_length : str2_length;
3425
3426 // No need to flatten if we are going to find the answer on the first
3427 // character. At this point we know there is at least one character
3428 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003429 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430 if (d != 0) return Smi::FromInt(d);
3431
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003432 str1->TryFlatten();
3433 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003435 StringInputBuffer& buf1 =
3436 *isolate->runtime_state()->string_locale_compare_buf1();
3437 StringInputBuffer& buf2 =
3438 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439
3440 buf1.Reset(str1);
3441 buf2.Reset(str2);
3442
3443 for (int i = 0; i < end; i++) {
3444 uint16_t char1 = buf1.GetNext();
3445 uint16_t char2 = buf2.GetNext();
3446 if (char1 != char2) return Smi::FromInt(char1 - char2);
3447 }
3448
3449 return Smi::FromInt(str1_length - str2_length);
3450}
3451
3452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003453RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454 NoHandleAllocation ha;
3455 ASSERT(args.length() == 3);
3456
3457 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003458 int start, end;
3459 // We have a fast integer-only case here to avoid a conversion to double in
3460 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003461 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3462 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3463 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3464 start = from_number;
3465 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003466 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003467 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3468 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003469 start = FastD2I(from_number);
3470 end = FastD2I(to_number);
3471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 RUNTIME_ASSERT(end >= start);
3473 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003474 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003475 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003476 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003477}
3478
3479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003480RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003481 ASSERT_EQ(3, args.length());
3482
3483 CONVERT_ARG_CHECKED(String, subject, 0);
3484 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3485 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3486 HandleScope handles;
3487
3488 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3489
3490 if (match.is_null()) {
3491 return Failure::Exception();
3492 }
3493 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003495 }
3496 int length = subject->length();
3497
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003498 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003499 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003500 int start;
3501 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003502 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003503 {
3504 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003505 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003506 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3507 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3508 }
3509 offsets.Add(start);
3510 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003511 if (start == end) if (++end > length) break;
3512 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003513 if (match.is_null()) {
3514 return Failure::Exception();
3515 }
3516 } while (!match->IsNull());
3517 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003518 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003519 Handle<String> substring = isolate->factory()->
3520 NewSubString(subject, offsets.at(0), offsets.at(1));
3521 elements->set(0, *substring);
3522 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003523 int from = offsets.at(i * 2);
3524 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003525 Handle<String> substring = isolate->factory()->
3526 NewProperSubString(subject, from, to);
3527 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003528 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003530 result->set_length(Smi::FromInt(matches));
3531 return *result;
3532}
3533
3534
lrn@chromium.org25156de2010-04-06 13:10:27 +00003535// Two smis before and after the match, for very long strings.
3536const int kMaxBuilderEntriesPerRegExpMatch = 5;
3537
3538
3539static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3540 Handle<JSArray> last_match_info,
3541 int match_start,
3542 int match_end) {
3543 // Fill last_match_info with a single capture.
3544 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3545 AssertNoAllocation no_gc;
3546 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3547 RegExpImpl::SetLastCaptureCount(elements, 2);
3548 RegExpImpl::SetLastInput(elements, *subject);
3549 RegExpImpl::SetLastSubject(elements, *subject);
3550 RegExpImpl::SetCapture(elements, 0, match_start);
3551 RegExpImpl::SetCapture(elements, 1, match_end);
3552}
3553
3554
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003555template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003556static bool SearchStringMultiple(Isolate* isolate,
3557 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003558 Vector<const PatternChar> pattern,
3559 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003560 FixedArrayBuilder* builder,
3561 int* match_pos) {
3562 int pos = *match_pos;
3563 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003564 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003565 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003567 while (pos <= max_search_start) {
3568 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3569 *match_pos = pos;
3570 return false;
3571 }
3572 // Position of end of previous match.
3573 int match_end = pos + pattern_length;
3574 int new_pos = search.Search(subject, match_end);
3575 if (new_pos >= 0) {
3576 // A match.
3577 if (new_pos > match_end) {
3578 ReplacementStringBuilder::AddSubjectSlice(builder,
3579 match_end,
3580 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003581 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003582 pos = new_pos;
3583 builder->Add(pattern_string);
3584 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003585 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003586 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003587 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003588
lrn@chromium.org25156de2010-04-06 13:10:27 +00003589 if (pos < max_search_start) {
3590 ReplacementStringBuilder::AddSubjectSlice(builder,
3591 pos + pattern_length,
3592 subject_length);
3593 }
3594 *match_pos = pos;
3595 return true;
3596}
3597
3598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003599static bool SearchStringMultiple(Isolate* isolate,
3600 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003601 Handle<String> pattern,
3602 Handle<JSArray> last_match_info,
3603 FixedArrayBuilder* builder) {
3604 ASSERT(subject->IsFlat());
3605 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003606
3607 // Treating as if a previous match was before first character.
3608 int match_pos = -pattern->length();
3609
3610 for (;;) { // Break when search complete.
3611 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3612 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003613 String::FlatContent subject_content = subject->GetFlatContent();
3614 String::FlatContent pattern_content = pattern->GetFlatContent();
3615 if (subject_content.IsAscii()) {
3616 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3617 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 if (SearchStringMultiple(isolate,
3619 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003620 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003621 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003622 builder,
3623 &match_pos)) break;
3624 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 if (SearchStringMultiple(isolate,
3626 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003627 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003628 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003629 builder,
3630 &match_pos)) break;
3631 }
3632 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003633 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3634 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003635 if (SearchStringMultiple(isolate,
3636 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003637 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003638 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003639 builder,
3640 &match_pos)) break;
3641 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 if (SearchStringMultiple(isolate,
3643 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003644 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003645 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003646 builder,
3647 &match_pos)) break;
3648 }
3649 }
3650 }
3651
3652 if (match_pos >= 0) {
3653 SetLastMatchInfoNoCaptures(subject,
3654 last_match_info,
3655 match_pos,
3656 match_pos + pattern->length());
3657 return true;
3658 }
3659 return false; // No matches at all.
3660}
3661
3662
3663static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003665 Handle<String> subject,
3666 Handle<JSRegExp> regexp,
3667 Handle<JSArray> last_match_array,
3668 FixedArrayBuilder* builder) {
3669 ASSERT(subject->IsFlat());
3670 int match_start = -1;
3671 int match_end = 0;
3672 int pos = 0;
3673 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3674 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3675
3676 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003677 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003679 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003680
3681 for (;;) { // Break on failure, return on exception.
3682 RegExpImpl::IrregexpResult result =
3683 RegExpImpl::IrregexpExecOnce(regexp,
3684 subject,
3685 pos,
3686 register_vector);
3687 if (result == RegExpImpl::RE_SUCCESS) {
3688 match_start = register_vector[0];
3689 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3690 if (match_end < match_start) {
3691 ReplacementStringBuilder::AddSubjectSlice(builder,
3692 match_end,
3693 match_start);
3694 }
3695 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003697 if (!first) {
3698 builder->Add(*isolate->factory()->NewProperSubString(subject,
3699 match_start,
3700 match_end));
3701 } else {
3702 builder->Add(*isolate->factory()->NewSubString(subject,
3703 match_start,
3704 match_end));
3705 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003706 if (match_start != match_end) {
3707 pos = match_end;
3708 } else {
3709 pos = match_end + 1;
3710 if (pos > subject_length) break;
3711 }
3712 } else if (result == RegExpImpl::RE_FAILURE) {
3713 break;
3714 } else {
3715 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3716 return result;
3717 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003718 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 }
3720
3721 if (match_start >= 0) {
3722 if (match_end < subject_length) {
3723 ReplacementStringBuilder::AddSubjectSlice(builder,
3724 match_end,
3725 subject_length);
3726 }
3727 SetLastMatchInfoNoCaptures(subject,
3728 last_match_array,
3729 match_start,
3730 match_end);
3731 return RegExpImpl::RE_SUCCESS;
3732 } else {
3733 return RegExpImpl::RE_FAILURE; // No matches at all.
3734 }
3735}
3736
3737
3738static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003740 Handle<String> subject,
3741 Handle<JSRegExp> regexp,
3742 Handle<JSArray> last_match_array,
3743 FixedArrayBuilder* builder) {
3744
3745 ASSERT(subject->IsFlat());
3746 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3747 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3748
3749 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003750 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003751
3752 RegExpImpl::IrregexpResult result =
3753 RegExpImpl::IrregexpExecOnce(regexp,
3754 subject,
3755 0,
3756 register_vector);
3757
3758 int capture_count = regexp->CaptureCount();
3759 int subject_length = subject->length();
3760
3761 // Position to search from.
3762 int pos = 0;
3763 // End of previous match. Differs from pos if match was empty.
3764 int match_end = 0;
3765 if (result == RegExpImpl::RE_SUCCESS) {
3766 // Need to keep a copy of the previous match for creating last_match_info
3767 // at the end, so we have two vectors that we swap between.
3768 OffsetsVector registers2(required_registers);
3769 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003770 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003771 do {
3772 int match_start = register_vector[0];
3773 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3774 if (match_end < match_start) {
3775 ReplacementStringBuilder::AddSubjectSlice(builder,
3776 match_end,
3777 match_start);
3778 }
3779 match_end = register_vector[1];
3780
3781 {
3782 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003783 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003784 // Arguments array to replace function is match, captures, index and
3785 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003786 Handle<FixedArray> elements =
3787 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003788 Handle<String> match;
3789 if (!first) {
3790 match = isolate->factory()->NewProperSubString(subject,
3791 match_start,
3792 match_end);
3793 } else {
3794 match = isolate->factory()->NewSubString(subject,
3795 match_start,
3796 match_end);
3797 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003798 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003799 for (int i = 1; i <= capture_count; i++) {
3800 int start = register_vector[i * 2];
3801 if (start >= 0) {
3802 int end = register_vector[i * 2 + 1];
3803 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003804 Handle<String> substring;
3805 if (!first) {
3806 substring = isolate->factory()->NewProperSubString(subject,
3807 start,
3808 end);
3809 } else {
3810 substring = isolate->factory()->NewSubString(subject, start, end);
3811 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003812 elements->set(i, *substring);
3813 } else {
3814 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003815 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003816 }
3817 }
3818 elements->set(capture_count + 1, Smi::FromInt(match_start));
3819 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003820 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003821 }
3822 // Swap register vectors, so the last successful match is in
3823 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003824 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003825 prev_register_vector = register_vector;
3826 register_vector = tmp;
3827
3828 if (match_end > match_start) {
3829 pos = match_end;
3830 } else {
3831 pos = match_end + 1;
3832 if (pos > subject_length) {
3833 break;
3834 }
3835 }
3836
3837 result = RegExpImpl::IrregexpExecOnce(regexp,
3838 subject,
3839 pos,
3840 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003841 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003842 } while (result == RegExpImpl::RE_SUCCESS);
3843
3844 if (result != RegExpImpl::RE_EXCEPTION) {
3845 // Finished matching, with at least one match.
3846 if (match_end < subject_length) {
3847 ReplacementStringBuilder::AddSubjectSlice(builder,
3848 match_end,
3849 subject_length);
3850 }
3851
3852 int last_match_capture_count = (capture_count + 1) * 2;
3853 int last_match_array_size =
3854 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3855 last_match_array->EnsureSize(last_match_array_size);
3856 AssertNoAllocation no_gc;
3857 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3858 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3859 RegExpImpl::SetLastSubject(elements, *subject);
3860 RegExpImpl::SetLastInput(elements, *subject);
3861 for (int i = 0; i < last_match_capture_count; i++) {
3862 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3863 }
3864 return RegExpImpl::RE_SUCCESS;
3865 }
3866 }
3867 // No matches at all, return failure or exception result directly.
3868 return result;
3869}
3870
3871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003872RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003873 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003875
3876 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003877 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003878 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3879 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3880 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3881
3882 ASSERT(last_match_info->HasFastElements());
3883 ASSERT(regexp->GetFlags().is_global());
3884 Handle<FixedArray> result_elements;
3885 if (result_array->HasFastElements()) {
3886 result_elements =
3887 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003888 }
3889 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 }
3892 FixedArrayBuilder builder(result_elements);
3893
3894 if (regexp->TypeTag() == JSRegExp::ATOM) {
3895 Handle<String> pattern(
3896 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003897 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003898 if (SearchStringMultiple(isolate, subject, pattern,
3899 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003900 return *builder.ToJSArray(result_array);
3901 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003902 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003903 }
3904
3905 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3906
3907 RegExpImpl::IrregexpResult result;
3908 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 result = SearchRegExpNoCaptureMultiple(isolate,
3910 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003911 regexp,
3912 last_match_info,
3913 &builder);
3914 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003915 result = SearchRegExpMultiple(isolate,
3916 subject,
3917 regexp,
3918 last_match_info,
3919 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003920 }
3921 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3924 return Failure::Exception();
3925}
3926
3927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003928RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003929 NoHandleAllocation ha;
3930 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003931 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003932 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003934 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003935 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003936 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003937 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003938 // Character array used for conversion.
3939 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 return isolate->heap()->
3941 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003942 }
3943 }
3944
3945 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003946 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003948 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 }
3950 if (isinf(value)) {
3951 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003952 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003954 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003957 MaybeObject* result =
3958 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 DeleteArray(str);
3960 return result;
3961}
3962
3963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003964RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 NoHandleAllocation ha;
3966 ASSERT(args.length() == 2);
3967
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003968 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003970 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
3972 if (isinf(value)) {
3973 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003974 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003976 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003978 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 int f = FastD2I(f_number);
3980 RUNTIME_ASSERT(f >= 0);
3981 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 MaybeObject* res =
3983 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003985 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986}
3987
3988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003989RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 NoHandleAllocation ha;
3991 ASSERT(args.length() == 2);
3992
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003993 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003995 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 }
3997 if (isinf(value)) {
3998 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003999 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004001 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004002 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004003 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 int f = FastD2I(f_number);
4005 RUNTIME_ASSERT(f >= -1 && f <= 20);
4006 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 MaybeObject* res =
4008 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004010 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011}
4012
4013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004014RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 NoHandleAllocation ha;
4016 ASSERT(args.length() == 2);
4017
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004018 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004020 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 }
4022 if (isinf(value)) {
4023 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004024 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004026 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004028 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 int f = FastD2I(f_number);
4030 RUNTIME_ASSERT(f >= 1 && f <= 21);
4031 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004032 MaybeObject* res =
4033 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004035 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036}
4037
4038
4039// Returns a single character string where first character equals
4040// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004041static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004042 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004043 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004044 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004045 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004047 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048}
4049
4050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004051MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4052 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004053 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 // Handle [] indexing on Strings
4055 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4057 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 }
4059
4060 // Handle [] indexing on String objects
4061 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004062 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4063 Handle<Object> result =
4064 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4065 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 }
4067
4068 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004069 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070 return prototype->GetElement(index);
4071 }
4072
4073 return object->GetElement(index);
4074}
4075
4076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004077MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4078 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004079 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004083 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004085 isolate->factory()->NewTypeError("non_object_property_load",
4086 HandleVector(args, 2));
4087 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 }
4089
4090 // Check if the given key is an array index.
4091 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004092 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004093 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 }
4095
4096 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004097 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004099 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 bool has_pending_exception = false;
4102 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004103 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004105 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 }
4107
ager@chromium.org32912102009-01-16 10:38:43 +00004108 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 // the element if so.
4110 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004111 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004113 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 }
4115}
4116
4117
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004118RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 NoHandleAllocation ha;
4120 ASSERT(args.length() == 2);
4121
4122 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004123 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004125 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126}
4127
4128
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004129MaybeObject* TransitionElements(Handle<Object> object,
4130 ElementsKind to_kind,
4131 Isolate* isolate) {
4132 HandleScope scope(isolate);
4133 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4134 ElementsKind from_kind =
4135 Handle<JSObject>::cast(object)->map()->elements_kind();
4136 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4137 Handle<Object> result =
4138 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4139 if (result.is_null()) return isolate->ThrowIllegalOperation();
4140 return *result;
4141 }
4142 return isolate->ThrowIllegalOperation();
4143}
4144
4145
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004146// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004147RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004148 NoHandleAllocation ha;
4149 ASSERT(args.length() == 2);
4150
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004151 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004152 // itself.
4153 //
4154 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004155 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004156 // global proxy object never has properties. This is the case
4157 // because the global proxy object forwards everything to its hidden
4158 // prototype including local lookups.
4159 //
4160 // Additionally, we need to make sure that we do not cache results
4161 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004162 if (args[0]->IsJSObject()) {
4163 if (!args[0]->IsJSGlobalProxy() &&
4164 !args[0]->IsAccessCheckNeeded() &&
4165 args[1]->IsString()) {
4166 JSObject* receiver = JSObject::cast(args[0]);
4167 String* key = String::cast(args[1]);
4168 if (receiver->HasFastProperties()) {
4169 // Attempt to use lookup cache.
4170 Map* receiver_map = receiver->map();
4171 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4172 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4173 if (offset != -1) {
4174 Object* value = receiver->FastPropertyAt(offset);
4175 return value->IsTheHole()
4176 ? isolate->heap()->undefined_value()
4177 : value;
4178 }
4179 // Lookup cache miss. Perform lookup and update the cache if
4180 // appropriate.
4181 LookupResult result(isolate);
4182 receiver->LocalLookup(key, &result);
4183 if (result.IsProperty() && result.type() == FIELD) {
4184 int offset = result.GetFieldIndex();
4185 keyed_lookup_cache->Update(receiver_map, key, offset);
4186 return receiver->FastPropertyAt(offset);
4187 }
4188 } else {
4189 // Attempt dictionary lookup.
4190 StringDictionary* dictionary = receiver->property_dictionary();
4191 int entry = dictionary->FindEntry(key);
4192 if ((entry != StringDictionary::kNotFound) &&
4193 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4194 Object* value = dictionary->ValueAt(entry);
4195 if (!receiver->IsGlobalObject()) return value;
4196 value = JSGlobalPropertyCell::cast(value)->value();
4197 if (!value->IsTheHole()) return value;
4198 // If value is the hole do the general lookup.
4199 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004200 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004201 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4202 // JSObject without a string key. If the key is a Smi, check for a
4203 // definite out-of-bounds access to elements, which is a strong indicator
4204 // that subsequent accesses will also call the runtime. Proactively
4205 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4206 // doubles for those future calls in the case that the elements would
4207 // become FAST_DOUBLE_ELEMENTS.
4208 Handle<JSObject> js_object(args.at<JSObject>(0));
4209 ElementsKind elements_kind = js_object->GetElementsKind();
4210 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4211 elements_kind == FAST_DOUBLE_ELEMENTS) {
4212 FixedArrayBase* elements = js_object->elements();
4213 if (args.at<Smi>(1)->value() >= elements->length()) {
4214 MaybeObject* maybe_object = TransitionElements(js_object,
4215 FAST_ELEMENTS,
4216 isolate);
4217 if (maybe_object->IsFailure()) return maybe_object;
4218 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004219 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004220 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004221 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4222 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004223 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004224 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004225 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004226 if (index >= 0 && index < str->length()) {
4227 Handle<Object> result = GetCharAt(str, index);
4228 return *result;
4229 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004230 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004231
4232 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004233 return Runtime::GetObjectProperty(isolate,
4234 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004235 args.at<Object>(1));
4236}
4237
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004238// Implements part of 8.12.9 DefineOwnProperty.
4239// There are 3 cases that lead here:
4240// Step 4b - define a new accessor property.
4241// Steps 9c & 12 - replace an existing data property with an accessor property.
4242// Step 12 - update an existing accessor property with an accessor or generic
4243// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004244RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004245 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004246 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004247 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4248 CONVERT_CHECKED(String, name, args[1]);
4249 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004250 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004251 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004252
ager@chromium.org5c838252010-02-19 08:53:10 +00004253 int unchecked = flag_attr->value();
4254 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004255 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004256
4257 RUNTIME_ASSERT(!obj->IsNull());
4258 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004259 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4260}
4261
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004262// Implements part of 8.12.9 DefineOwnProperty.
4263// There are 3 cases that lead here:
4264// Step 4a - define a new data property.
4265// Steps 9b & 12 - replace an existing accessor property with a data property.
4266// Step 12 - update an existing data property with a data or generic
4267// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004268RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004269 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004270 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004271 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4272 CONVERT_ARG_CHECKED(String, name, 1);
4273 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004274 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004275
ager@chromium.org5c838252010-02-19 08:53:10 +00004276 int unchecked = flag->value();
4277 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004278 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4279
4280 // Check if this is an element.
4281 uint32_t index;
4282 bool is_element = name->AsArrayIndex(&index);
4283
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004284 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004285 // If elements are in fast case we always implicitly assume that:
4286 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004287 if (is_element && (attr != NONE ||
4288 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004289 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004290 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004291 // We do not need to do access checks here since these has already
4292 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004293 Handle<Object> proto(js_object->GetPrototype());
4294 // If proxy is detached, ignore the assignment. Alternatively,
4295 // we could throw an exception.
4296 if (proto->IsNull()) return *obj_value;
4297 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004298 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004299
4300 // Don't allow element properties to be redefined on objects with external
4301 // array elements.
4302 if (js_object->HasExternalArrayElements()) {
4303 Handle<Object> args[2] = { js_object, name };
4304 Handle<Object> error =
4305 isolate->factory()->NewTypeError("redef_external_array_element",
4306 HandleVector(args, 2));
4307 return isolate->Throw(*error);
4308 }
4309
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004310 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004311 // Make sure that we never go back to fast case.
4312 dictionary->set_requires_slow_elements();
4313 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004314 Handle<NumberDictionary> extended_dictionary =
4315 NumberDictionarySet(dictionary, index, obj_value, details);
4316 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004317 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004318 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4319 } else {
4320 js_object->set_elements(*extended_dictionary);
4321 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004322 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004323 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004324 }
4325
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004326 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004327 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004328
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004329 // To be compatible with safari we do not change the value on API objects
4330 // in defineProperty. Firefox disagrees here, and actually changes the value.
4331 if (result.IsProperty() &&
4332 (result.type() == CALLBACKS) &&
4333 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004334 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004335 }
4336
ager@chromium.org5c838252010-02-19 08:53:10 +00004337 // Take special care when attributes are different and there is already
4338 // a property. For simplicity we normalize the property which enables us
4339 // to not worry about changing the instance_descriptor and creating a new
4340 // map. The current version of SetObjectProperty does not handle attributes
4341 // correctly in the case where a property is a field and is reset with
4342 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004343 if (result.IsProperty() &&
4344 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004345 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004346 if (js_object->IsJSGlobalProxy()) {
4347 // Since the result is a property, the prototype will exist so
4348 // we don't have to check for null.
4349 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004350 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004351 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004352 // Use IgnoreAttributes version since a readonly property may be
4353 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004354 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4355 *obj_value,
4356 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004357 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004358
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004359 return Runtime::ForceSetObjectProperty(isolate,
4360 js_object,
4361 name,
4362 obj_value,
4363 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004364}
4365
4366
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004367// Special case for elements if any of the flags are true.
4368// If elements are in fast case we always implicitly assume that:
4369// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4370static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4371 Handle<JSObject> js_object,
4372 uint32_t index,
4373 Handle<Object> value,
4374 PropertyAttributes attr) {
4375 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004376 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004377 // Make sure that we never go back to fast case.
4378 dictionary->set_requires_slow_elements();
4379 PropertyDetails details = PropertyDetails(attr, NORMAL);
4380 Handle<NumberDictionary> extended_dictionary =
4381 NumberDictionarySet(dictionary, index, value, details);
4382 if (*extended_dictionary != *dictionary) {
4383 js_object->set_elements(*extended_dictionary);
4384 }
4385 return *value;
4386}
4387
4388
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004389MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4390 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004391 Handle<Object> key,
4392 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004393 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004394 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004395 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004397 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004398 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004399 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004400 isolate->factory()->NewTypeError("non_object_property_store",
4401 HandleVector(args, 2));
4402 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004403 }
4404
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004405 if (object->IsJSProxy()) {
4406 bool has_pending_exception = false;
4407 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4408 if (has_pending_exception) return Failure::Exception();
4409 return JSProxy::cast(*object)->SetProperty(
4410 String::cast(*name), *value, attr, strict_mode);
4411 }
4412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004413 // If the object isn't a JavaScript object, we ignore the store.
4414 if (!object->IsJSObject()) return *value;
4415
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004416 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004418 // Check if the given key is an array index.
4419 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004420 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004421 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4422 // of a string using [] notation. We need to support this too in
4423 // JavaScript.
4424 // In the case of a String object we just need to redirect the assignment to
4425 // the underlying string if the index is in range. Since the underlying
4426 // string does nothing with the assignment then we can ignore such
4427 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004428 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004429 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004430 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004432 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4433 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4434 }
4435
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004436 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004437 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 return *value;
4439 }
4440
4441 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004442 Handle<Object> result;
4443 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004444 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4445 return NormalizeObjectSetElement(isolate,
4446 js_object,
4447 index,
4448 value,
4449 attr);
4450 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004451 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004452 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004453 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004454 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004455 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004457 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004458 return *value;
4459 }
4460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004461 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004462 bool has_pending_exception = false;
4463 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4464 if (has_pending_exception) return Failure::Exception();
4465 Handle<String> name = Handle<String>::cast(converted);
4466
4467 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004468 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004469 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004470 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 }
4472}
4473
4474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004475MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4476 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004477 Handle<Object> key,
4478 Handle<Object> value,
4479 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004480 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004481
4482 // Check if the given key is an array index.
4483 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004484 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004485 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4486 // of a string using [] notation. We need to support this too in
4487 // JavaScript.
4488 // In the case of a String object we just need to redirect the assignment to
4489 // the underlying string if the index is in range. Since the underlying
4490 // string does nothing with the assignment then we can ignore such
4491 // assignments.
4492 if (js_object->IsStringObjectWithCharacterAt(index)) {
4493 return *value;
4494 }
4495
whesse@chromium.org7b260152011-06-20 15:33:18 +00004496 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004497 }
4498
4499 if (key->IsString()) {
4500 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004501 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004502 } else {
4503 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004504 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004505 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4506 *value,
4507 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004508 }
4509 }
4510
4511 // Call-back into JavaScript to convert the key to a string.
4512 bool has_pending_exception = false;
4513 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4514 if (has_pending_exception) return Failure::Exception();
4515 Handle<String> name = Handle<String>::cast(converted);
4516
4517 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004518 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004519 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004520 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004521 }
4522}
4523
4524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004525MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004526 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004527 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004528 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004529
4530 // Check if the given key is an array index.
4531 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004532 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004533 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4534 // characters of a string using [] notation. In the case of a
4535 // String object we just need to redirect the deletion to the
4536 // underlying string if the index is in range. Since the
4537 // underlying string does nothing with the deletion, we can ignore
4538 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004539 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004540 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004541 }
4542
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004543 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004544 }
4545
4546 Handle<String> key_string;
4547 if (key->IsString()) {
4548 key_string = Handle<String>::cast(key);
4549 } else {
4550 // Call-back into JavaScript to convert the key to a string.
4551 bool has_pending_exception = false;
4552 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4553 if (has_pending_exception) return Failure::Exception();
4554 key_string = Handle<String>::cast(converted);
4555 }
4556
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004557 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004558 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004559}
4560
4561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004562RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004564 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565
4566 Handle<Object> object = args.at<Object>(0);
4567 Handle<Object> key = args.at<Object>(1);
4568 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004569 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004570 RUNTIME_ASSERT(
4571 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004572 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004573 PropertyAttributes attributes =
4574 static_cast<PropertyAttributes>(unchecked_attributes);
4575
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004576 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004577 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004578 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4579 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 return Runtime::SetObjectProperty(isolate,
4583 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004584 key,
4585 value,
4586 attributes,
4587 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588}
4589
4590
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004591RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4592 NoHandleAllocation ha;
4593 RUNTIME_ASSERT(args.length() == 1);
4594 Handle<Object> object = args.at<Object>(0);
4595 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4596}
4597
4598
4599RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4600 NoHandleAllocation ha;
4601 RUNTIME_ASSERT(args.length() == 1);
4602 Handle<Object> object = args.at<Object>(0);
4603 return TransitionElements(object, FAST_ELEMENTS, isolate);
4604}
4605
4606
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004607// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004608// This is used to decide if we should transform null and undefined
4609// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004610RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004611 NoHandleAllocation ha;
4612 RUNTIME_ASSERT(args.length() == 1);
4613
4614 Handle<Object> object = args.at<Object>(0);
4615
4616 if (object->IsJSFunction()) {
4617 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004618 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004619 }
4620 return isolate->heap()->undefined_value();
4621}
4622
4623
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004624RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4625 RUNTIME_ASSERT(args.length() == 5);
4626 CONVERT_ARG_CHECKED(JSObject, object, 0);
4627 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4628 Handle<Object> value = args.at<Object>(2);
4629 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4630 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4631 HandleScope scope;
4632
4633 Object* raw_boilerplate_object = literals->get(literal_index);
4634 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4635#if DEBUG
4636 ElementsKind elements_kind = object->GetElementsKind();
4637#endif
4638 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4639 // Smis should never trigger transitions.
4640 ASSERT(!value->IsSmi());
4641
4642 if (value->IsNumber()) {
4643 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4644 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004645 TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004646 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4647 FixedDoubleArray* double_array =
4648 FixedDoubleArray::cast(object->elements());
4649 HeapNumber* number = HeapNumber::cast(*value);
4650 double_array->set(store_index, number->Number());
4651 } else {
4652 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4653 elements_kind == FAST_DOUBLE_ELEMENTS);
4654 TransitionElementsKind(object, FAST_ELEMENTS);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004655 TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004656 FixedArray* object_array =
4657 FixedArray::cast(object->elements());
4658 object_array->set(store_index, *value);
4659 }
4660 return *object;
4661}
4662
4663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004664// Set a local property, even if it is READ_ONLY. If the property does not
4665// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004666RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004667 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004668 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 CONVERT_CHECKED(JSObject, object, args[0]);
4670 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004671 // Compute attributes.
4672 PropertyAttributes attributes = NONE;
4673 if (args.length() == 4) {
4674 CONVERT_CHECKED(Smi, value_obj, args[3]);
4675 int unchecked_value = value_obj->value();
4676 // Only attribute bits should be set.
4677 RUNTIME_ASSERT(
4678 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4679 attributes = static_cast<PropertyAttributes>(unchecked_value);
4680 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004682 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004683 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684}
4685
4686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004687RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004689 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004691 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004692 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004693 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4694 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004695 ? JSReceiver::STRICT_DELETION
4696 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697}
4698
4699
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004700static Object* HasLocalPropertyImplementation(Isolate* isolate,
4701 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004702 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004703 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004704 // Handle hidden prototypes. If there's a hidden prototype above this thing
4705 // then we have to check it for properties, because they are supposed to
4706 // look like they are on this object.
4707 Handle<Object> proto(object->GetPrototype());
4708 if (proto->IsJSObject() &&
4709 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004710 return HasLocalPropertyImplementation(isolate,
4711 Handle<JSObject>::cast(proto),
4712 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004713 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004714 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004715}
4716
4717
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004718RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 NoHandleAllocation ha;
4720 ASSERT(args.length() == 2);
4721 CONVERT_CHECKED(String, key, args[1]);
4722
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004723 uint32_t index;
4724 const bool key_is_array_index = key->AsArrayIndex(&index);
4725
ager@chromium.org9085a012009-05-11 19:22:57 +00004726 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004728 if (obj->IsJSObject()) {
4729 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004730 // Fast case: either the key is a real named property or it is not
4731 // an array index and there are no interceptors or hidden
4732 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004733 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004734 Map* map = object->map();
4735 if (!key_is_array_index &&
4736 !map->has_named_interceptor() &&
4737 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4738 return isolate->heap()->false_value();
4739 }
4740 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004741 HandleScope scope(isolate);
4742 return HasLocalPropertyImplementation(isolate,
4743 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004744 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004745 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004746 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004747 String* string = String::cast(obj);
4748 if (index < static_cast<uint32_t>(string->length())) {
4749 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750 }
4751 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004752 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753}
4754
4755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004756RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 NoHandleAllocation na;
4758 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004759 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4760 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004762 bool result = receiver->HasProperty(key);
4763 if (isolate->has_pending_exception()) return Failure::Exception();
4764 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765}
4766
4767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004768RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 NoHandleAllocation na;
4770 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004771 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4772 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004774 bool result = receiver->HasElement(index->value());
4775 if (isolate->has_pending_exception()) return Failure::Exception();
4776 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777}
4778
4779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004780RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 NoHandleAllocation ha;
4782 ASSERT(args.length() == 2);
4783
4784 CONVERT_CHECKED(JSObject, object, args[0]);
4785 CONVERT_CHECKED(String, key, args[1]);
4786
4787 uint32_t index;
4788 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004789 JSObject::LocalElementType type = object->HasLocalElement(index);
4790 switch (type) {
4791 case JSObject::UNDEFINED_ELEMENT:
4792 case JSObject::STRING_CHARACTER_ELEMENT:
4793 return isolate->heap()->false_value();
4794 case JSObject::INTERCEPTED_ELEMENT:
4795 case JSObject::FAST_ELEMENT:
4796 return isolate->heap()->true_value();
4797 case JSObject::DICTIONARY_ELEMENT: {
4798 if (object->IsJSGlobalProxy()) {
4799 Object* proto = object->GetPrototype();
4800 if (proto->IsNull()) {
4801 return isolate->heap()->false_value();
4802 }
4803 ASSERT(proto->IsJSGlobalObject());
4804 object = JSObject::cast(proto);
4805 }
4806 FixedArray* elements = FixedArray::cast(object->elements());
4807 NumberDictionary* dictionary = NULL;
4808 if (elements->map() ==
4809 isolate->heap()->non_strict_arguments_elements_map()) {
4810 dictionary = NumberDictionary::cast(elements->get(1));
4811 } else {
4812 dictionary = NumberDictionary::cast(elements);
4813 }
4814 int entry = dictionary->FindEntry(index);
4815 ASSERT(entry != NumberDictionary::kNotFound);
4816 PropertyDetails details = dictionary->DetailsAt(entry);
4817 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4818 }
4819 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820 }
4821
ager@chromium.org870a0b62008-11-04 11:43:05 +00004822 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004823 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824}
4825
4826
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004828 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004829 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004830 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4831 bool threw = false;
4832 Handle<JSArray> result = GetKeysFor(object, &threw);
4833 if (threw) return Failure::Exception();
4834 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004835}
4836
4837
4838// Returns either a FixedArray as Runtime_GetPropertyNames,
4839// or, if the given object has an enum cache that contains
4840// all enumerable properties of the object and its prototypes
4841// have none, the map of the object. This is used to speed up
4842// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004843RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844 ASSERT(args.length() == 1);
4845
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004846 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847
4848 if (raw_object->IsSimpleEnum()) return raw_object->map();
4849
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004850 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004851 Handle<JSReceiver> object(raw_object);
4852 bool threw = false;
4853 Handle<FixedArray> content =
4854 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4855 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856
4857 // Test again, since cache may have been built by preceding call.
4858 if (object->IsSimpleEnum()) return object->map();
4859
4860 return *content;
4861}
4862
4863
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004864// Find the length of the prototype chain that is to to handled as one. If a
4865// prototype object is hidden it is to be viewed as part of the the object it
4866// is prototype for.
4867static int LocalPrototypeChainLength(JSObject* obj) {
4868 int count = 1;
4869 Object* proto = obj->GetPrototype();
4870 while (proto->IsJSObject() &&
4871 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4872 count++;
4873 proto = JSObject::cast(proto)->GetPrototype();
4874 }
4875 return count;
4876}
4877
4878
4879// Return the names of the local named properties.
4880// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004881RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004882 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004883 ASSERT(args.length() == 1);
4884 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004885 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004886 }
4887 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4888
4889 // Skip the global proxy as it has no properties and always delegates to the
4890 // real global object.
4891 if (obj->IsJSGlobalProxy()) {
4892 // Only collect names if access is permitted.
4893 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 !isolate->MayNamedAccess(*obj,
4895 isolate->heap()->undefined_value(),
4896 v8::ACCESS_KEYS)) {
4897 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4898 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004899 }
4900 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4901 }
4902
4903 // Find the number of objects making up this.
4904 int length = LocalPrototypeChainLength(*obj);
4905
4906 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004907 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004908 int total_property_count = 0;
4909 Handle<JSObject> jsproto = obj;
4910 for (int i = 0; i < length; i++) {
4911 // Only collect names if access is permitted.
4912 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004913 !isolate->MayNamedAccess(*jsproto,
4914 isolate->heap()->undefined_value(),
4915 v8::ACCESS_KEYS)) {
4916 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4917 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004918 }
4919 int n;
4920 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4921 local_property_count[i] = n;
4922 total_property_count += n;
4923 if (i < length - 1) {
4924 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4925 }
4926 }
4927
4928 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004929 Handle<FixedArray> names =
4930 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004931
4932 // Get the property names.
4933 jsproto = obj;
4934 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004935 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004936 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004937 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4938 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004939 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004940 proto_with_hidden_properties++;
4941 }
4942 if (i < length - 1) {
4943 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4944 }
4945 }
4946
4947 // Filter out name of hidden propeties object.
4948 if (proto_with_hidden_properties > 0) {
4949 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004950 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004951 names->length() - proto_with_hidden_properties);
4952 int dest_pos = 0;
4953 for (int i = 0; i < total_property_count; i++) {
4954 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004955 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004956 continue;
4957 }
4958 names->set(dest_pos++, name);
4959 }
4960 }
4961
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004962 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004963}
4964
4965
4966// Return the names of the local indexed properties.
4967// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004968RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004969 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004970 ASSERT(args.length() == 1);
4971 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004972 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004973 }
4974 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4975
4976 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004978 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004980}
4981
4982
4983// Return information on whether an object has a named or indexed interceptor.
4984// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004985RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004986 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004987 ASSERT(args.length() == 1);
4988 if (!args[0]->IsJSObject()) {
4989 return Smi::FromInt(0);
4990 }
4991 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4992
4993 int result = 0;
4994 if (obj->HasNamedInterceptor()) result |= 2;
4995 if (obj->HasIndexedInterceptor()) result |= 1;
4996
4997 return Smi::FromInt(result);
4998}
4999
5000
5001// Return property names from named interceptor.
5002// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005003RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005004 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005005 ASSERT(args.length() == 1);
5006 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5007
5008 if (obj->HasNamedInterceptor()) {
5009 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5010 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5011 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005012 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005013}
5014
5015
5016// Return element names from indexed interceptor.
5017// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005018RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005019 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005020 ASSERT(args.length() == 1);
5021 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5022
5023 if (obj->HasIndexedInterceptor()) {
5024 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5025 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5026 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005027 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005028}
5029
5030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005031RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005032 ASSERT_EQ(args.length(), 1);
5033 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005034 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005035 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005036
5037 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005038 // Do access checks before going to the global object.
5039 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005041 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005042 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5043 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005044 }
5045
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005046 Handle<Object> proto(object->GetPrototype());
5047 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005048 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005049 object = Handle<JSObject>::cast(proto);
5050 }
5051
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005052 bool threw = false;
5053 Handle<FixedArray> contents =
5054 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5055 if (threw) return Failure::Exception();
5056
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005057 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5058 // property array and since the result is mutable we have to create
5059 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005060 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005061 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005062 for (int i = 0; i < length; i++) {
5063 Object* entry = contents->get(i);
5064 if (entry->IsString()) {
5065 copy->set(i, entry);
5066 } else {
5067 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 HandleScope scope(isolate);
5069 Handle<Object> entry_handle(entry, isolate);
5070 Handle<Object> entry_str =
5071 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005072 copy->set(i, *entry_str);
5073 }
5074 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005076}
5077
5078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005079RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005080 NoHandleAllocation ha;
5081 ASSERT(args.length() == 1);
5082
5083 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005084 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005085 it.AdvanceToArgumentsFrame();
5086 JavaScriptFrame* frame = it.frame();
5087
5088 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005089 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005090
5091 // Try to convert the key to an index. If successful and within
5092 // index return the the argument from the frame.
5093 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005094 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 return frame->GetParameter(index);
5096 }
5097
5098 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005099 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005100 bool exception = false;
5101 Handle<Object> converted =
5102 Execution::ToString(args.at<Object>(0), &exception);
5103 if (exception) return Failure::Exception();
5104 Handle<String> key = Handle<String>::cast(converted);
5105
5106 // Try to convert the string key into an array index.
5107 if (key->AsArrayIndex(&index)) {
5108 if (index < n) {
5109 return frame->GetParameter(index);
5110 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005111 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005112 }
5113 }
5114
5115 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005116 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5117 if (key->Equals(isolate->heap()->callee_symbol())) {
5118 Object* function = frame->function();
5119 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005120 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005121 return isolate->Throw(*isolate->factory()->NewTypeError(
5122 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5123 }
5124 return function;
5125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005126
5127 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005128 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005129}
5130
5131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005132RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005133 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005134
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005135 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005136 Handle<Object> object = args.at<Object>(0);
5137 if (object->IsJSObject()) {
5138 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005139 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005140 MaybeObject* ok = js_object->TransformToFastProperties(0);
5141 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005142 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005143 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005144 return *object;
5145}
5146
5147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005148RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005149 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005150
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005151 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005152 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005153 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005154 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005155 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005156 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005157 return *object;
5158}
5159
5160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005161RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005162 NoHandleAllocation ha;
5163 ASSERT(args.length() == 1);
5164
5165 return args[0]->ToBoolean();
5166}
5167
5168
5169// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5170// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005171RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005172 NoHandleAllocation ha;
5173
5174 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005175 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176 HeapObject* heap_obj = HeapObject::cast(obj);
5177
5178 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005179 if (heap_obj->map()->is_undetectable()) {
5180 return isolate->heap()->undefined_symbol();
5181 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182
5183 InstanceType instance_type = heap_obj->map()->instance_type();
5184 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005185 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186 }
5187
5188 switch (instance_type) {
5189 case ODDBALL_TYPE:
5190 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005191 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005192 }
5193 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005194 return FLAG_harmony_typeof
5195 ? isolate->heap()->null_symbol()
5196 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197 }
5198 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005199 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005200 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005201 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005202 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005203 default:
5204 // For any kind of object not handled above, the spec rule for
5205 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005206 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005207 }
5208}
5209
5210
lrn@chromium.org25156de2010-04-06 13:10:27 +00005211static bool AreDigits(const char*s, int from, int to) {
5212 for (int i = from; i < to; i++) {
5213 if (s[i] < '0' || s[i] > '9') return false;
5214 }
5215
5216 return true;
5217}
5218
5219
5220static int ParseDecimalInteger(const char*s, int from, int to) {
5221 ASSERT(to - from < 10); // Overflow is not possible.
5222 ASSERT(from < to);
5223 int d = s[from] - '0';
5224
5225 for (int i = from + 1; i < to; i++) {
5226 d = 10 * d + (s[i] - '0');
5227 }
5228
5229 return d;
5230}
5231
5232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005233RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234 NoHandleAllocation ha;
5235 ASSERT(args.length() == 1);
5236 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005237 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005238
5239 // Fast case: short integer or some sorts of junk values.
5240 int len = subject->length();
5241 if (subject->IsSeqAsciiString()) {
5242 if (len == 0) return Smi::FromInt(0);
5243
5244 char const* data = SeqAsciiString::cast(subject)->GetChars();
5245 bool minus = (data[0] == '-');
5246 int start_pos = (minus ? 1 : 0);
5247
5248 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005249 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005250 } else if (data[start_pos] > '9') {
5251 // Fast check for a junk value. A valid string may start from a
5252 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5253 // the 'I' character ('Infinity'). All of that have codes not greater than
5254 // '9' except 'I'.
5255 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005256 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005257 }
5258 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5259 // The maximal/minimal smi has 10 digits. If the string has less digits we
5260 // know it will fit into the smi-data type.
5261 int d = ParseDecimalInteger(data, start_pos, len);
5262 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005263 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005264 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005265 } else if (!subject->HasHashCode() &&
5266 len <= String::kMaxArrayIndexSize &&
5267 (len == 1 || data[0] != '0')) {
5268 // String hash is not calculated yet but all the data are present.
5269 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005270 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005271#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005272 subject->Hash(); // Force hash calculation.
5273 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5274 static_cast<int>(hash));
5275#endif
5276 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005277 }
5278 return Smi::FromInt(d);
5279 }
5280 }
5281
5282 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005283 return isolate->heap()->NumberFromDouble(
5284 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285}
5286
5287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005288RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005289 NoHandleAllocation ha;
5290 ASSERT(args.length() == 1);
5291
5292 CONVERT_CHECKED(JSArray, codes, args[0]);
5293 int length = Smi::cast(codes->length())->value();
5294
5295 // Check if the string can be ASCII.
5296 int i;
5297 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005298 Object* element;
5299 { MaybeObject* maybe_element = codes->GetElement(i);
5300 // We probably can't get an exception here, but just in order to enforce
5301 // the checking of inputs in the runtime calls we check here.
5302 if (!maybe_element->ToObject(&element)) return maybe_element;
5303 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005304 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5305 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5306 break;
5307 }
5308
lrn@chromium.org303ada72010-10-27 09:33:13 +00005309 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005310 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005311 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005313 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005314 }
5315
lrn@chromium.org303ada72010-10-27 09:33:13 +00005316 Object* object = NULL;
5317 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318 String* result = String::cast(object);
5319 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005320 Object* element;
5321 { MaybeObject* maybe_element = codes->GetElement(i);
5322 if (!maybe_element->ToObject(&element)) return maybe_element;
5323 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005325 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005326 }
5327 return result;
5328}
5329
5330
5331// kNotEscaped is generated by the following:
5332//
5333// #!/bin/perl
5334// for (my $i = 0; $i < 256; $i++) {
5335// print "\n" if $i % 16 == 0;
5336// my $c = chr($i);
5337// my $escaped = 1;
5338// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5339// print $escaped ? "0, " : "1, ";
5340// }
5341
5342
5343static bool IsNotEscaped(uint16_t character) {
5344 // Only for 8 bit characters, the rest are always escaped (in a different way)
5345 ASSERT(character < 256);
5346 static const char kNotEscaped[256] = {
5347 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5353 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5363 };
5364 return kNotEscaped[character] != 0;
5365}
5366
5367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005368RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005369 const char hex_chars[] = "0123456789ABCDEF";
5370 NoHandleAllocation ha;
5371 ASSERT(args.length() == 1);
5372 CONVERT_CHECKED(String, source, args[0]);
5373
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005374 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005375
5376 int escaped_length = 0;
5377 int length = source->length();
5378 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005379 Access<StringInputBuffer> buffer(
5380 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005381 buffer->Reset(source);
5382 while (buffer->has_more()) {
5383 uint16_t character = buffer->GetNext();
5384 if (character >= 256) {
5385 escaped_length += 6;
5386 } else if (IsNotEscaped(character)) {
5387 escaped_length++;
5388 } else {
5389 escaped_length += 3;
5390 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005391 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005392 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005393 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005394 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 return Failure::OutOfMemoryException();
5396 }
5397 }
5398 }
5399 // No length change implies no change. Return original string if no change.
5400 if (escaped_length == length) {
5401 return source;
5402 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005403 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005404 { MaybeObject* maybe_o =
5405 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005406 if (!maybe_o->ToObject(&o)) return maybe_o;
5407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408 String* destination = String::cast(o);
5409 int dest_position = 0;
5410
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005411 Access<StringInputBuffer> buffer(
5412 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005413 buffer->Rewind();
5414 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005415 uint16_t chr = buffer->GetNext();
5416 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005417 destination->Set(dest_position, '%');
5418 destination->Set(dest_position+1, 'u');
5419 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5420 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5421 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5422 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005423 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005424 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005425 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005426 dest_position++;
5427 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005428 destination->Set(dest_position, '%');
5429 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5430 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 dest_position += 3;
5432 }
5433 }
5434 return destination;
5435}
5436
5437
5438static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5439 static const signed char kHexValue['g'] = {
5440 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5441 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5442 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5443 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5444 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5445 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5446 -1, 10, 11, 12, 13, 14, 15 };
5447
5448 if (character1 > 'f') return -1;
5449 int hi = kHexValue[character1];
5450 if (hi == -1) return -1;
5451 if (character2 > 'f') return -1;
5452 int lo = kHexValue[character2];
5453 if (lo == -1) return -1;
5454 return (hi << 4) + lo;
5455}
5456
5457
ager@chromium.org870a0b62008-11-04 11:43:05 +00005458static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005459 int i,
5460 int length,
5461 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005463 int32_t hi = 0;
5464 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 if (character == '%' &&
5466 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005467 source->Get(i + 1) == 'u' &&
5468 (hi = TwoDigitHex(source->Get(i + 2),
5469 source->Get(i + 3))) != -1 &&
5470 (lo = TwoDigitHex(source->Get(i + 4),
5471 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005472 *step = 6;
5473 return (hi << 8) + lo;
5474 } else if (character == '%' &&
5475 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 (lo = TwoDigitHex(source->Get(i + 1),
5477 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005478 *step = 3;
5479 return lo;
5480 } else {
5481 *step = 1;
5482 return character;
5483 }
5484}
5485
5486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005487RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005488 NoHandleAllocation ha;
5489 ASSERT(args.length() == 1);
5490 CONVERT_CHECKED(String, source, args[0]);
5491
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005492 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005493
5494 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005495 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005496
5497 int unescaped_length = 0;
5498 for (int i = 0; i < length; unescaped_length++) {
5499 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005500 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005503 i += step;
5504 }
5505
5506 // No length change implies no change. Return original string if no change.
5507 if (unescaped_length == length)
5508 return source;
5509
lrn@chromium.org303ada72010-10-27 09:33:13 +00005510 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005511 { MaybeObject* maybe_o =
5512 ascii ?
5513 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5514 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005515 if (!maybe_o->ToObject(&o)) return maybe_o;
5516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005517 String* destination = String::cast(o);
5518
5519 int dest_position = 0;
5520 for (int i = 0; i < length; dest_position++) {
5521 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005522 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523 i += step;
5524 }
5525 return destination;
5526}
5527
5528
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005529static const unsigned int kQuoteTableLength = 128u;
5530
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005531static const int kJsonQuotesCharactersPerEntry = 8;
5532static const char* const JsonQuotes =
5533 "\\u0000 \\u0001 \\u0002 \\u0003 "
5534 "\\u0004 \\u0005 \\u0006 \\u0007 "
5535 "\\b \\t \\n \\u000b "
5536 "\\f \\r \\u000e \\u000f "
5537 "\\u0010 \\u0011 \\u0012 \\u0013 "
5538 "\\u0014 \\u0015 \\u0016 \\u0017 "
5539 "\\u0018 \\u0019 \\u001a \\u001b "
5540 "\\u001c \\u001d \\u001e \\u001f "
5541 " ! \\\" # "
5542 "$ % & ' "
5543 "( ) * + "
5544 ", - . / "
5545 "0 1 2 3 "
5546 "4 5 6 7 "
5547 "8 9 : ; "
5548 "< = > ? "
5549 "@ A B C "
5550 "D E F G "
5551 "H I J K "
5552 "L M N O "
5553 "P Q R S "
5554 "T U V W "
5555 "X Y Z [ "
5556 "\\\\ ] ^ _ "
5557 "` a b c "
5558 "d e f g "
5559 "h i j k "
5560 "l m n o "
5561 "p q r s "
5562 "t u v w "
5563 "x y z { "
5564 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005565
5566
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005567// For a string that is less than 32k characters it should always be
5568// possible to allocate it in new space.
5569static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5570
5571
5572// Doing JSON quoting cannot make the string more than this many times larger.
5573static const int kJsonQuoteWorstCaseBlowup = 6;
5574
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005575static const int kSpaceForQuotesAndComma = 3;
5576static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005577
5578// Covers the entire ASCII range (all other characters are unchanged by JSON
5579// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005580static const byte JsonQuoteLengths[kQuoteTableLength] = {
5581 6, 6, 6, 6, 6, 6, 6, 6,
5582 2, 2, 2, 6, 2, 2, 6, 6,
5583 6, 6, 6, 6, 6, 6, 6, 6,
5584 6, 6, 6, 6, 6, 6, 6, 6,
5585 1, 1, 2, 1, 1, 1, 1, 1,
5586 1, 1, 1, 1, 1, 1, 1, 1,
5587 1, 1, 1, 1, 1, 1, 1, 1,
5588 1, 1, 1, 1, 1, 1, 1, 1,
5589 1, 1, 1, 1, 1, 1, 1, 1,
5590 1, 1, 1, 1, 1, 1, 1, 1,
5591 1, 1, 1, 1, 1, 1, 1, 1,
5592 1, 1, 1, 1, 2, 1, 1, 1,
5593 1, 1, 1, 1, 1, 1, 1, 1,
5594 1, 1, 1, 1, 1, 1, 1, 1,
5595 1, 1, 1, 1, 1, 1, 1, 1,
5596 1, 1, 1, 1, 1, 1, 1, 1,
5597};
5598
5599
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005600template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005601MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005602
5603
5604template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005605MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5606 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005607}
5608
5609
5610template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005611MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5612 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005613}
5614
5615
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005616template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005617static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5618 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005619 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005620 const Char* read_cursor = characters.start();
5621 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005622 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005623 int quoted_length = kSpaceForQuotes;
5624 while (read_cursor < end) {
5625 Char c = *(read_cursor++);
5626 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5627 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005628 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005629 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005630 }
5631 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005632 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5633 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005634 Object* new_object;
5635 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005636 return new_alloc;
5637 }
5638 StringType* new_string = StringType::cast(new_object);
5639
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005640 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005641 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005642 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005643 *(write_cursor++) = '"';
5644
5645 read_cursor = characters.start();
5646 while (read_cursor < end) {
5647 Char c = *(read_cursor++);
5648 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5649 *(write_cursor++) = c;
5650 } else {
5651 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5652 const char* replacement = JsonQuotes +
5653 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5654 for (int i = 0; i < len; i++) {
5655 *write_cursor++ = *replacement++;
5656 }
5657 }
5658 }
5659 *(write_cursor++) = '"';
5660 return new_string;
5661}
5662
5663
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005664template <typename SinkChar, typename SourceChar>
5665static inline SinkChar* WriteQuoteJsonString(
5666 Isolate* isolate,
5667 SinkChar* write_cursor,
5668 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005669 // SinkChar is only char if SourceChar is guaranteed to be char.
5670 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005671 const SourceChar* read_cursor = characters.start();
5672 const SourceChar* end = read_cursor + characters.length();
5673 *(write_cursor++) = '"';
5674 while (read_cursor < end) {
5675 SourceChar c = *(read_cursor++);
5676 if (sizeof(SourceChar) > 1u &&
5677 static_cast<unsigned>(c) >= kQuoteTableLength) {
5678 *(write_cursor++) = static_cast<SinkChar>(c);
5679 } else {
5680 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5681 const char* replacement = JsonQuotes +
5682 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5683 write_cursor[0] = replacement[0];
5684 if (len > 1) {
5685 write_cursor[1] = replacement[1];
5686 if (len > 2) {
5687 ASSERT(len == 6);
5688 write_cursor[2] = replacement[2];
5689 write_cursor[3] = replacement[3];
5690 write_cursor[4] = replacement[4];
5691 write_cursor[5] = replacement[5];
5692 }
5693 }
5694 write_cursor += len;
5695 }
5696 }
5697 *(write_cursor++) = '"';
5698 return write_cursor;
5699}
5700
5701
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005702template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005703static MaybeObject* QuoteJsonString(Isolate* isolate,
5704 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005705 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005706 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005707 int worst_case_length =
5708 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005709 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005710 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005711 }
5712
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005713 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5714 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005715 Object* new_object;
5716 if (!new_alloc->ToObject(&new_object)) {
5717 return new_alloc;
5718 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005719 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005720 // Even if our string is small enough to fit in new space we still have to
5721 // handle it being allocated in old space as may happen in the third
5722 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5723 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005724 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005725 }
5726 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005727 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005728
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005729 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005730 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005731 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005732 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5733 write_cursor,
5734 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005735 int final_length = static_cast<int>(
5736 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005737 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005738 isolate->heap()->new_space()->
5739 template ShrinkStringAtAllocationBoundary<StringType>(
5740 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005741 return new_string;
5742}
5743
5744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005745RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005746 NoHandleAllocation ha;
5747 CONVERT_CHECKED(String, str, args[0]);
5748 if (!str->IsFlat()) {
5749 MaybeObject* try_flatten = str->TryFlatten();
5750 Object* flat;
5751 if (!try_flatten->ToObject(&flat)) {
5752 return try_flatten;
5753 }
5754 str = String::cast(flat);
5755 ASSERT(str->IsFlat());
5756 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005757 String::FlatContent flat = str->GetFlatContent();
5758 ASSERT(flat.IsFlat());
5759 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005760 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005761 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005762 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005763 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005764 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005765 }
5766}
5767
5768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005769RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005770 NoHandleAllocation ha;
5771 CONVERT_CHECKED(String, str, args[0]);
5772 if (!str->IsFlat()) {
5773 MaybeObject* try_flatten = str->TryFlatten();
5774 Object* flat;
5775 if (!try_flatten->ToObject(&flat)) {
5776 return try_flatten;
5777 }
5778 str = String::cast(flat);
5779 ASSERT(str->IsFlat());
5780 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005781 String::FlatContent flat = str->GetFlatContent();
5782 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005783 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005784 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005785 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005786 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005787 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005788 }
5789}
5790
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005791
5792template <typename Char, typename StringType>
5793static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5794 FixedArray* array,
5795 int worst_case_length) {
5796 int length = array->length();
5797
5798 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5799 worst_case_length);
5800 Object* new_object;
5801 if (!new_alloc->ToObject(&new_object)) {
5802 return new_alloc;
5803 }
5804 if (!isolate->heap()->new_space()->Contains(new_object)) {
5805 // Even if our string is small enough to fit in new space we still have to
5806 // handle it being allocated in old space as may happen in the third
5807 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5808 // CEntryStub::GenerateCore.
5809 return isolate->heap()->undefined_value();
5810 }
5811 AssertNoAllocation no_gc;
5812 StringType* new_string = StringType::cast(new_object);
5813 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5814
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005815 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005816 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005817 *(write_cursor++) = '[';
5818 for (int i = 0; i < length; i++) {
5819 if (i != 0) *(write_cursor++) = ',';
5820 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005821 String::FlatContent content = str->GetFlatContent();
5822 ASSERT(content.IsFlat());
5823 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005824 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5825 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005826 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005827 } else {
5828 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5829 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005830 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005831 }
5832 }
5833 *(write_cursor++) = ']';
5834
5835 int final_length = static_cast<int>(
5836 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005837 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005838 isolate->heap()->new_space()->
5839 template ShrinkStringAtAllocationBoundary<StringType>(
5840 new_string, final_length);
5841 return new_string;
5842}
5843
5844
5845RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5846 NoHandleAllocation ha;
5847 ASSERT(args.length() == 1);
5848 CONVERT_CHECKED(JSArray, array, args[0]);
5849
5850 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5851 FixedArray* elements = FixedArray::cast(array->elements());
5852 int n = elements->length();
5853 bool ascii = true;
5854 int total_length = 0;
5855
5856 for (int i = 0; i < n; i++) {
5857 Object* elt = elements->get(i);
5858 if (!elt->IsString()) return isolate->heap()->undefined_value();
5859 String* element = String::cast(elt);
5860 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5861 total_length += element->length();
5862 if (ascii && element->IsTwoByteRepresentation()) {
5863 ascii = false;
5864 }
5865 }
5866
5867 int worst_case_length =
5868 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5869 + total_length * kJsonQuoteWorstCaseBlowup;
5870
5871 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5872 return isolate->heap()->undefined_value();
5873 }
5874
5875 if (ascii) {
5876 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5877 elements,
5878 worst_case_length);
5879 } else {
5880 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5881 elements,
5882 worst_case_length);
5883 }
5884}
5885
5886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005887RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005888 NoHandleAllocation ha;
5889
5890 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005891 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005893 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894
lrn@chromium.org25156de2010-04-06 13:10:27 +00005895 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005896 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005897 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005898}
5899
5900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005901RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902 NoHandleAllocation ha;
5903 CONVERT_CHECKED(String, str, args[0]);
5904
5905 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005906 double value = StringToDouble(isolate->unicode_cache(),
5907 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908
5909 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911}
5912
5913
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005915MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005916 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005917 String* s,
5918 int length,
5919 int input_string_length,
5920 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005921 // We try this twice, once with the assumption that the result is no longer
5922 // than the input and, if that assumption breaks, again with the exact
5923 // length. This may not be pretty, but it is nicer than what was here before
5924 // and I hereby claim my vaffel-is.
5925 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926 // Allocate the resulting string.
5927 //
5928 // NOTE: This assumes that the upper/lower case of an ascii
5929 // character is also ascii. This is currently the case, but it
5930 // might break in the future if we implement more context and locale
5931 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005932 Object* o;
5933 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005934 ? isolate->heap()->AllocateRawAsciiString(length)
5935 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005936 if (!maybe_o->ToObject(&o)) return maybe_o;
5937 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938 String* result = String::cast(o);
5939 bool has_changed_character = false;
5940
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941 // Convert all characters to upper case, assuming that they will fit
5942 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005943 Access<StringInputBuffer> buffer(
5944 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005946 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947 // We can assume that the string is not empty
5948 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005949 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005950 bool has_next = buffer->has_more();
5951 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952 int char_length = mapping->get(current, next, chars);
5953 if (char_length == 0) {
5954 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005955 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 i++;
5957 } else if (char_length == 1) {
5958 // Common case: converting the letter resulted in one character.
5959 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005960 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961 has_changed_character = true;
5962 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005963 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964 // We've assumed that the result would be as long as the
5965 // input but here is a character that converts to several
5966 // characters. No matter, we calculate the exact length
5967 // of the result and try the whole thing again.
5968 //
5969 // Note that this leaves room for optimization. We could just
5970 // memcpy what we already have to the result string. Also,
5971 // the result string is the last object allocated we could
5972 // "realloc" it and probably, in the vast majority of cases,
5973 // extend the existing string to be able to hold the full
5974 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005975 int next_length = 0;
5976 if (has_next) {
5977 next_length = mapping->get(next, 0, chars);
5978 if (next_length == 0) next_length = 1;
5979 }
5980 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 while (buffer->has_more()) {
5982 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005983 // NOTE: we use 0 as the next character here because, while
5984 // the next character may affect what a character converts to,
5985 // it does not in any case affect the length of what it convert
5986 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 int char_length = mapping->get(current, 0, chars);
5988 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005989 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005990 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005991 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005992 return Failure::OutOfMemoryException();
5993 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005995 // Try again with the real length.
5996 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 } else {
5998 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005999 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000 i++;
6001 }
6002 has_changed_character = true;
6003 }
6004 current = next;
6005 }
6006 if (has_changed_character) {
6007 return result;
6008 } else {
6009 // If we didn't actually change anything in doing the conversion
6010 // we simple return the result and let the converted string
6011 // become garbage; there is no reason to keep two identical strings
6012 // alive.
6013 return s;
6014 }
6015}
6016
6017
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006018namespace {
6019
lrn@chromium.org303ada72010-10-27 09:33:13 +00006020static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6021
6022
6023// Given a word and two range boundaries returns a word with high bit
6024// set in every byte iff the corresponding input byte was strictly in
6025// the range (m, n). All the other bits in the result are cleared.
6026// This function is only useful when it can be inlined and the
6027// boundaries are statically known.
6028// Requires: all bytes in the input word and the boundaries must be
6029// ascii (less than 0x7F).
6030static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6031 // Every byte in an ascii string is less than or equal to 0x7F.
6032 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6033 // Use strict inequalities since in edge cases the function could be
6034 // further simplified.
6035 ASSERT(0 < m && m < n && n < 0x7F);
6036 // Has high bit set in every w byte less than n.
6037 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6038 // Has high bit set in every w byte greater than m.
6039 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6040 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6041}
6042
6043
6044enum AsciiCaseConversion {
6045 ASCII_TO_LOWER,
6046 ASCII_TO_UPPER
6047};
6048
6049
6050template <AsciiCaseConversion dir>
6051struct FastAsciiConverter {
6052 static bool Convert(char* dst, char* src, int length) {
6053#ifdef DEBUG
6054 char* saved_dst = dst;
6055 char* saved_src = src;
6056#endif
6057 // We rely on the distance between upper and lower case letters
6058 // being a known power of 2.
6059 ASSERT('a' - 'A' == (1 << 5));
6060 // Boundaries for the range of input characters than require conversion.
6061 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6062 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6063 bool changed = false;
6064 char* const limit = src + length;
6065#ifdef V8_HOST_CAN_READ_UNALIGNED
6066 // Process the prefix of the input that requires no conversion one
6067 // (machine) word at a time.
6068 while (src <= limit - sizeof(uintptr_t)) {
6069 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6070 if (AsciiRangeMask(w, lo, hi) != 0) {
6071 changed = true;
6072 break;
6073 }
6074 *reinterpret_cast<uintptr_t*>(dst) = w;
6075 src += sizeof(uintptr_t);
6076 dst += sizeof(uintptr_t);
6077 }
6078 // Process the remainder of the input performing conversion when
6079 // required one word at a time.
6080 while (src <= limit - sizeof(uintptr_t)) {
6081 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6082 uintptr_t m = AsciiRangeMask(w, lo, hi);
6083 // The mask has high (7th) bit set in every byte that needs
6084 // conversion and we know that the distance between cases is
6085 // 1 << 5.
6086 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6087 src += sizeof(uintptr_t);
6088 dst += sizeof(uintptr_t);
6089 }
6090#endif
6091 // Process the last few bytes of the input (or the whole input if
6092 // unaligned access is not supported).
6093 while (src < limit) {
6094 char c = *src;
6095 if (lo < c && c < hi) {
6096 c ^= (1 << 5);
6097 changed = true;
6098 }
6099 *dst = c;
6100 ++src;
6101 ++dst;
6102 }
6103#ifdef DEBUG
6104 CheckConvert(saved_dst, saved_src, length, changed);
6105#endif
6106 return changed;
6107 }
6108
6109#ifdef DEBUG
6110 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6111 bool expected_changed = false;
6112 for (int i = 0; i < length; i++) {
6113 if (dst[i] == src[i]) continue;
6114 expected_changed = true;
6115 if (dir == ASCII_TO_LOWER) {
6116 ASSERT('A' <= src[i] && src[i] <= 'Z');
6117 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6118 } else {
6119 ASSERT(dir == ASCII_TO_UPPER);
6120 ASSERT('a' <= src[i] && src[i] <= 'z');
6121 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6122 }
6123 }
6124 ASSERT(expected_changed == changed);
6125 }
6126#endif
6127};
6128
6129
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006130struct ToLowerTraits {
6131 typedef unibrow::ToLowercase UnibrowConverter;
6132
lrn@chromium.org303ada72010-10-27 09:33:13 +00006133 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006134};
6135
6136
6137struct ToUpperTraits {
6138 typedef unibrow::ToUppercase UnibrowConverter;
6139
lrn@chromium.org303ada72010-10-27 09:33:13 +00006140 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006141};
6142
6143} // namespace
6144
6145
6146template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006147MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006149 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006150 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006151 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006152 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006153 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006154
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006155 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006156 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006157 if (length == 0) return s;
6158
6159 // Simpler handling of ascii strings.
6160 //
6161 // NOTE: This assumes that the upper/lower case of an ascii
6162 // character is also ascii. This is currently the case, but it
6163 // might break in the future if we implement more context and locale
6164 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006165 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006166 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006167 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006168 if (!maybe_o->ToObject(&o)) return maybe_o;
6169 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006170 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006171 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006172 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006173 return has_changed_character ? result : s;
6174 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006175
lrn@chromium.org303ada72010-10-27 09:33:13 +00006176 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006177 { MaybeObject* maybe_answer =
6178 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006179 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6180 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006181 if (answer->IsSmi()) {
6182 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006183 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006184 ConvertCaseHelper(isolate,
6185 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006186 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6187 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006188 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006189 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006190}
6191
6192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006193RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006194 return ConvertCase<ToLowerTraits>(
6195 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006196}
6197
6198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006199RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006200 return ConvertCase<ToUpperTraits>(
6201 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006202}
6203
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006204
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006205static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006206 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006207}
6208
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006210RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006211 NoHandleAllocation ha;
6212 ASSERT(args.length() == 3);
6213
6214 CONVERT_CHECKED(String, s, args[0]);
6215 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6216 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6217
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006218 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006219 int length = s->length();
6220
6221 int left = 0;
6222 if (trimLeft) {
6223 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6224 left++;
6225 }
6226 }
6227
6228 int right = length;
6229 if (trimRight) {
6230 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6231 right--;
6232 }
6233 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006234 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006235}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006238RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006239 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006240 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006241 CONVERT_ARG_CHECKED(String, subject, 0);
6242 CONVERT_ARG_CHECKED(String, pattern, 1);
6243 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6244
6245 int subject_length = subject->length();
6246 int pattern_length = pattern->length();
6247 RUNTIME_ASSERT(pattern_length > 0);
6248
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006249 if (limit == 0xffffffffu) {
6250 Handle<Object> cached_answer(StringSplitCache::Lookup(
6251 isolate->heap()->string_split_cache(),
6252 *subject,
6253 *pattern));
6254 if (*cached_answer != Smi::FromInt(0)) {
6255 Handle<JSArray> result =
6256 isolate->factory()->NewJSArrayWithElements(
6257 Handle<FixedArray>::cast(cached_answer));
6258 return *result;
6259 }
6260 }
6261
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006262 // The limit can be very large (0xffffffffu), but since the pattern
6263 // isn't empty, we can never create more parts than ~half the length
6264 // of the subject.
6265
6266 if (!subject->IsFlat()) FlattenString(subject);
6267
6268 static const int kMaxInitialListCapacity = 16;
6269
danno@chromium.org40cb8782011-05-25 07:58:50 +00006270 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006271
6272 // Find (up to limit) indices of separator and end-of-string in subject
6273 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6274 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006275 if (!pattern->IsFlat()) FlattenString(pattern);
6276
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006277 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006278
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006279 if (static_cast<uint32_t>(indices.length()) < limit) {
6280 indices.Add(subject_length);
6281 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006282
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006283 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006284
6285 // Create JSArray of substrings separated by separator.
6286 int part_count = indices.length();
6287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006288 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006289 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006290 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006291 result->set_length(Smi::FromInt(part_count));
6292
6293 ASSERT(result->HasFastElements());
6294
6295 if (part_count == 1 && indices.at(0) == subject_length) {
6296 FixedArray::cast(result->elements())->set(0, *subject);
6297 return *result;
6298 }
6299
6300 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6301 int part_start = 0;
6302 for (int i = 0; i < part_count; i++) {
6303 HandleScope local_loop_handle;
6304 int part_end = indices.at(i);
6305 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006306 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006307 elements->set(i, *substring);
6308 part_start = part_end + pattern_length;
6309 }
6310
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006311 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006312 if (result->HasFastElements()) {
6313 StringSplitCache::Enter(isolate->heap(),
6314 isolate->heap()->string_split_cache(),
6315 *subject,
6316 *pattern,
6317 *elements);
6318 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006319 }
6320
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006321 return *result;
6322}
6323
6324
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006325// Copies ascii characters to the given fixed array looking up
6326// one-char strings in the cache. Gives up on the first char that is
6327// not in the cache and fills the remainder with smi zeros. Returns
6328// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006329static int CopyCachedAsciiCharsToArray(Heap* heap,
6330 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006331 FixedArray* elements,
6332 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006333 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006334 FixedArray* ascii_cache = heap->single_character_string_cache();
6335 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006336 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006337 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006338 for (i = 0; i < length; ++i) {
6339 Object* value = ascii_cache->get(chars[i]);
6340 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006341 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006342 }
6343 if (i < length) {
6344 ASSERT(Smi::FromInt(0) == 0);
6345 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6346 }
6347#ifdef DEBUG
6348 for (int j = 0; j < length; ++j) {
6349 Object* element = elements->get(j);
6350 ASSERT(element == Smi::FromInt(0) ||
6351 (element->IsString() && String::cast(element)->LooksValid()));
6352 }
6353#endif
6354 return i;
6355}
6356
6357
6358// Converts a String to JSArray.
6359// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006360RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006361 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006362 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006363 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006364 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006365
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006366 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006367 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006368
6369 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006370 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006371 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006372 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006373 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 { MaybeObject* maybe_obj =
6375 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006376 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6377 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006378 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006379 String::FlatContent content = s->GetFlatContent();
6380 if (content.IsAscii()) {
6381 Vector<const char> chars = content.ToAsciiVector();
6382 // Note, this will initialize all elements (not only the prefix)
6383 // to prevent GC from seeing partially initialized array.
6384 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6385 chars.start(),
6386 *elements,
6387 length);
6388 } else {
6389 MemsetPointer(elements->data_start(),
6390 isolate->heap()->undefined_value(),
6391 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006392 }
6393 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006394 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006395 }
6396 for (int i = position; i < length; ++i) {
6397 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6398 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006399 }
6400
6401#ifdef DEBUG
6402 for (int i = 0; i < length; ++i) {
6403 ASSERT(String::cast(elements->get(i))->length() == 1);
6404 }
6405#endif
6406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006407 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006408}
6409
6410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006411RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006412 NoHandleAllocation ha;
6413 ASSERT(args.length() == 1);
6414 CONVERT_CHECKED(String, value, args[0]);
6415 return value->ToObject();
6416}
6417
6418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006419bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006420 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006421 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006422 return char_length == 0;
6423}
6424
6425
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006426RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006427 NoHandleAllocation ha;
6428 ASSERT(args.length() == 1);
6429
6430 Object* number = args[0];
6431 RUNTIME_ASSERT(number->IsNumber());
6432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434}
6435
6436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006437RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 1);
6440
6441 Object* number = args[0];
6442 RUNTIME_ASSERT(number->IsNumber());
6443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006445}
6446
6447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006448RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449 NoHandleAllocation ha;
6450 ASSERT(args.length() == 1);
6451
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006452 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006453
6454 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6455 if (number > 0 && number <= Smi::kMaxValue) {
6456 return Smi::FromInt(static_cast<int>(number));
6457 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006459}
6460
6461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006462RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006463 NoHandleAllocation ha;
6464 ASSERT(args.length() == 1);
6465
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006466 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006467
6468 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6469 if (number > 0 && number <= Smi::kMaxValue) {
6470 return Smi::FromInt(static_cast<int>(number));
6471 }
6472
6473 double double_value = DoubleToInteger(number);
6474 // Map both -0 and +0 to +0.
6475 if (double_value == 0) double_value = 0;
6476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006477 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006478}
6479
6480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006481RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006482 NoHandleAllocation ha;
6483 ASSERT(args.length() == 1);
6484
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006485 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006486 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006487}
6488
6489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006490RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006491 NoHandleAllocation ha;
6492 ASSERT(args.length() == 1);
6493
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006494 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006495
6496 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6497 if (number > 0 && number <= Smi::kMaxValue) {
6498 return Smi::FromInt(static_cast<int>(number));
6499 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006500 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006501}
6502
6503
ager@chromium.org870a0b62008-11-04 11:43:05 +00006504// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6505// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006506RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006507 NoHandleAllocation ha;
6508 ASSERT(args.length() == 1);
6509
6510 Object* obj = args[0];
6511 if (obj->IsSmi()) {
6512 return obj;
6513 }
6514 if (obj->IsHeapNumber()) {
6515 double value = HeapNumber::cast(obj)->value();
6516 int int_value = FastD2I(value);
6517 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6518 return Smi::FromInt(int_value);
6519 }
6520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006521 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006522}
6523
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006525RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006526 NoHandleAllocation ha;
6527 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006528 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006529}
6530
6531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 2);
6535
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006536 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6537 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006538 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539}
6540
6541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006542RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543 NoHandleAllocation ha;
6544 ASSERT(args.length() == 2);
6545
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006546 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6547 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006548 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549}
6550
6551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006552RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553 NoHandleAllocation ha;
6554 ASSERT(args.length() == 2);
6555
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006556 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6557 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006558 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559}
6560
6561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006562RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 NoHandleAllocation ha;
6564 ASSERT(args.length() == 1);
6565
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006566 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568}
6569
6570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006571RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006572 NoHandleAllocation ha;
6573 ASSERT(args.length() == 0);
6574
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006575 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006576}
6577
6578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006579RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580 NoHandleAllocation ha;
6581 ASSERT(args.length() == 2);
6582
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006583 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6584 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586}
6587
6588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006589RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590 NoHandleAllocation ha;
6591 ASSERT(args.length() == 2);
6592
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006593 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6594 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595
ager@chromium.org3811b432009-10-28 14:53:37 +00006596 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006597 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006598 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599}
6600
6601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006602RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603 NoHandleAllocation ha;
6604 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605 CONVERT_CHECKED(String, str1, args[0]);
6606 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 isolate->counters()->string_add_runtime()->Increment();
6608 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609}
6610
6611
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006612template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006613static inline void StringBuilderConcatHelper(String* special,
6614 sinkchar* sink,
6615 FixedArray* fixed_array,
6616 int array_length) {
6617 int position = 0;
6618 for (int i = 0; i < array_length; i++) {
6619 Object* element = fixed_array->get(i);
6620 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006621 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006622 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006623 int pos;
6624 int len;
6625 if (encoded_slice > 0) {
6626 // Position and length encoded in one smi.
6627 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6628 len = StringBuilderSubstringLength::decode(encoded_slice);
6629 } else {
6630 // Position and length encoded in two smis.
6631 Object* obj = fixed_array->get(++i);
6632 ASSERT(obj->IsSmi());
6633 pos = Smi::cast(obj)->value();
6634 len = -encoded_slice;
6635 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006636 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006637 sink + position,
6638 pos,
6639 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006640 position += len;
6641 } else {
6642 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006643 int element_length = string->length();
6644 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006645 position += element_length;
6646 }
6647 }
6648}
6649
6650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006651RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006653 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006655 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006656 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006657 return Failure::OutOfMemoryException();
6658 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006659 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006660 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006661
6662 // This assumption is used by the slice encoding in one or two smis.
6663 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6664
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006665 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006666 if (maybe_result->IsFailure()) return maybe_result;
6667
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006668 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 }
6672 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006673 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006674 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006675 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006676
6677 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006678 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 } else if (array_length == 1) {
6680 Object* first = fixed_array->get(0);
6681 if (first->IsString()) return first;
6682 }
6683
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006684 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685 int position = 0;
6686 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006687 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688 Object* elt = fixed_array->get(i);
6689 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006690 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006691 int smi_value = Smi::cast(elt)->value();
6692 int pos;
6693 int len;
6694 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006695 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006696 pos = StringBuilderSubstringPosition::decode(smi_value);
6697 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006698 } else {
6699 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006700 len = -smi_value;
6701 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006702 i++;
6703 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006705 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006706 Object* next_smi = fixed_array->get(i);
6707 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006709 }
6710 pos = Smi::cast(next_smi)->value();
6711 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006713 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006715 ASSERT(pos >= 0);
6716 ASSERT(len >= 0);
6717 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006718 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006719 }
6720 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 } else if (elt->IsString()) {
6722 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006723 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006724 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006725 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006727 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006729 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006731 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006732 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006733 return Failure::OutOfMemoryException();
6734 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006735 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006736 }
6737
6738 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006739 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006741 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 { MaybeObject* maybe_object =
6743 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006744 if (!maybe_object->ToObject(&object)) return maybe_object;
6745 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006746 SeqAsciiString* answer = SeqAsciiString::cast(object);
6747 StringBuilderConcatHelper(special,
6748 answer->GetChars(),
6749 fixed_array,
6750 array_length);
6751 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006753 { MaybeObject* maybe_object =
6754 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006755 if (!maybe_object->ToObject(&object)) return maybe_object;
6756 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006757 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6758 StringBuilderConcatHelper(special,
6759 answer->GetChars(),
6760 fixed_array,
6761 array_length);
6762 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764}
6765
6766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006767RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006768 NoHandleAllocation ha;
6769 ASSERT(args.length() == 3);
6770 CONVERT_CHECKED(JSArray, array, args[0]);
6771 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006772 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006773 return Failure::OutOfMemoryException();
6774 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006775 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006776 CONVERT_CHECKED(String, separator, args[2]);
6777
6778 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006779 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006780 }
6781 FixedArray* fixed_array = FixedArray::cast(array->elements());
6782 if (fixed_array->length() < array_length) {
6783 array_length = fixed_array->length();
6784 }
6785
6786 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006787 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006788 } else if (array_length == 1) {
6789 Object* first = fixed_array->get(0);
6790 if (first->IsString()) return first;
6791 }
6792
6793 int separator_length = separator->length();
6794 int max_nof_separators =
6795 (String::kMaxLength + separator_length - 1) / separator_length;
6796 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006797 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006798 return Failure::OutOfMemoryException();
6799 }
6800 int length = (array_length - 1) * separator_length;
6801 for (int i = 0; i < array_length; i++) {
6802 Object* element_obj = fixed_array->get(i);
6803 if (!element_obj->IsString()) {
6804 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006805 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006806 }
6807 String* element = String::cast(element_obj);
6808 int increment = element->length();
6809 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006811 return Failure::OutOfMemoryException();
6812 }
6813 length += increment;
6814 }
6815
6816 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006817 { MaybeObject* maybe_object =
6818 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006819 if (!maybe_object->ToObject(&object)) return maybe_object;
6820 }
6821 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6822
6823 uc16* sink = answer->GetChars();
6824#ifdef DEBUG
6825 uc16* end = sink + length;
6826#endif
6827
6828 String* first = String::cast(fixed_array->get(0));
6829 int first_length = first->length();
6830 String::WriteToFlat(first, sink, 0, first_length);
6831 sink += first_length;
6832
6833 for (int i = 1; i < array_length; i++) {
6834 ASSERT(sink + separator_length <= end);
6835 String::WriteToFlat(separator, sink, 0, separator_length);
6836 sink += separator_length;
6837
6838 String* element = String::cast(fixed_array->get(i));
6839 int element_length = element->length();
6840 ASSERT(sink + element_length <= end);
6841 String::WriteToFlat(element, sink, 0, element_length);
6842 sink += element_length;
6843 }
6844 ASSERT(sink == end);
6845
6846 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6847 return answer;
6848}
6849
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006850template <typename Char>
6851static void JoinSparseArrayWithSeparator(FixedArray* elements,
6852 int elements_length,
6853 uint32_t array_length,
6854 String* separator,
6855 Vector<Char> buffer) {
6856 int previous_separator_position = 0;
6857 int separator_length = separator->length();
6858 int cursor = 0;
6859 for (int i = 0; i < elements_length; i += 2) {
6860 int position = NumberToInt32(elements->get(i));
6861 String* string = String::cast(elements->get(i + 1));
6862 int string_length = string->length();
6863 if (string->length() > 0) {
6864 while (previous_separator_position < position) {
6865 String::WriteToFlat<Char>(separator, &buffer[cursor],
6866 0, separator_length);
6867 cursor += separator_length;
6868 previous_separator_position++;
6869 }
6870 String::WriteToFlat<Char>(string, &buffer[cursor],
6871 0, string_length);
6872 cursor += string->length();
6873 }
6874 }
6875 if (separator_length > 0) {
6876 // Array length must be representable as a signed 32-bit number,
6877 // otherwise the total string length would have been too large.
6878 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6879 int last_array_index = static_cast<int>(array_length - 1);
6880 while (previous_separator_position < last_array_index) {
6881 String::WriteToFlat<Char>(separator, &buffer[cursor],
6882 0, separator_length);
6883 cursor += separator_length;
6884 previous_separator_position++;
6885 }
6886 }
6887 ASSERT(cursor <= buffer.length());
6888}
6889
6890
6891RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6892 NoHandleAllocation ha;
6893 ASSERT(args.length() == 3);
6894 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006895 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6896 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006897 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6898 CONVERT_CHECKED(String, separator, args[2]);
6899 // elements_array is fast-mode JSarray of alternating positions
6900 // (increasing order) and strings.
6901 // array_length is length of original array (used to add separators);
6902 // separator is string to put between elements. Assumed to be non-empty.
6903
6904 // Find total length of join result.
6905 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006906 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006907 int max_string_length;
6908 if (is_ascii) {
6909 max_string_length = SeqAsciiString::kMaxLength;
6910 } else {
6911 max_string_length = SeqTwoByteString::kMaxLength;
6912 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006913 bool overflow = false;
6914 CONVERT_NUMBER_CHECKED(int, elements_length,
6915 Int32, elements_array->length());
6916 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6917 FixedArray* elements = FixedArray::cast(elements_array->elements());
6918 for (int i = 0; i < elements_length; i += 2) {
6919 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6920 CONVERT_CHECKED(String, string, elements->get(i + 1));
6921 int length = string->length();
6922 if (is_ascii && !string->IsAsciiRepresentation()) {
6923 is_ascii = false;
6924 max_string_length = SeqTwoByteString::kMaxLength;
6925 }
6926 if (length > max_string_length ||
6927 max_string_length - length < string_length) {
6928 overflow = true;
6929 break;
6930 }
6931 string_length += length;
6932 }
6933 int separator_length = separator->length();
6934 if (!overflow && separator_length > 0) {
6935 if (array_length <= 0x7fffffffu) {
6936 int separator_count = static_cast<int>(array_length) - 1;
6937 int remaining_length = max_string_length - string_length;
6938 if ((remaining_length / separator_length) >= separator_count) {
6939 string_length += separator_length * (array_length - 1);
6940 } else {
6941 // Not room for the separators within the maximal string length.
6942 overflow = true;
6943 }
6944 } else {
6945 // Nonempty separator and at least 2^31-1 separators necessary
6946 // means that the string is too large to create.
6947 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6948 overflow = true;
6949 }
6950 }
6951 if (overflow) {
6952 // Throw OutOfMemory exception for creating too large a string.
6953 V8::FatalProcessOutOfMemory("Array join result too large.");
6954 }
6955
6956 if (is_ascii) {
6957 MaybeObject* result_allocation =
6958 isolate->heap()->AllocateRawAsciiString(string_length);
6959 if (result_allocation->IsFailure()) return result_allocation;
6960 SeqAsciiString* result_string =
6961 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6962 JoinSparseArrayWithSeparator<char>(elements,
6963 elements_length,
6964 array_length,
6965 separator,
6966 Vector<char>(result_string->GetChars(),
6967 string_length));
6968 return result_string;
6969 } else {
6970 MaybeObject* result_allocation =
6971 isolate->heap()->AllocateRawTwoByteString(string_length);
6972 if (result_allocation->IsFailure()) return result_allocation;
6973 SeqTwoByteString* result_string =
6974 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6975 JoinSparseArrayWithSeparator<uc16>(elements,
6976 elements_length,
6977 array_length,
6978 separator,
6979 Vector<uc16>(result_string->GetChars(),
6980 string_length));
6981 return result_string;
6982 }
6983}
6984
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006986RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006987 NoHandleAllocation ha;
6988 ASSERT(args.length() == 2);
6989
6990 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6991 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006992 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006993}
6994
6995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006996RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006997 NoHandleAllocation ha;
6998 ASSERT(args.length() == 2);
6999
7000 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7001 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007002 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007003}
7004
7005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007006RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007 NoHandleAllocation ha;
7008 ASSERT(args.length() == 2);
7009
7010 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7011 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007012 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007013}
7014
7015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007016RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007017 NoHandleAllocation ha;
7018 ASSERT(args.length() == 1);
7019
7020 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007021 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022}
7023
7024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007025RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007026 NoHandleAllocation ha;
7027 ASSERT(args.length() == 2);
7028
7029 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7030 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007031 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032}
7033
7034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007035RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036 NoHandleAllocation ha;
7037 ASSERT(args.length() == 2);
7038
7039 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7040 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007041 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042}
7043
7044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007045RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007046 NoHandleAllocation ha;
7047 ASSERT(args.length() == 2);
7048
7049 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7050 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007051 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052}
7053
7054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007055RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056 NoHandleAllocation ha;
7057 ASSERT(args.length() == 2);
7058
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007059 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7060 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7062 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7063 if (x == y) return Smi::FromInt(EQUAL);
7064 Object* result;
7065 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7066 result = Smi::FromInt(EQUAL);
7067 } else {
7068 result = Smi::FromInt(NOT_EQUAL);
7069 }
7070 return result;
7071}
7072
7073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007074RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075 NoHandleAllocation ha;
7076 ASSERT(args.length() == 2);
7077
7078 CONVERT_CHECKED(String, x, args[0]);
7079 CONVERT_CHECKED(String, y, args[1]);
7080
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007081 bool not_equal = !x->Equals(y);
7082 // This is slightly convoluted because the value that signifies
7083 // equality is 0 and inequality is 1 so we have to negate the result
7084 // from String::Equals.
7085 ASSERT(not_equal == 0 || not_equal == 1);
7086 STATIC_CHECK(EQUAL == 0);
7087 STATIC_CHECK(NOT_EQUAL == 1);
7088 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089}
7090
7091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007092RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 NoHandleAllocation ha;
7094 ASSERT(args.length() == 3);
7095
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007096 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7097 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 if (isnan(x) || isnan(y)) return args[2];
7099 if (x == y) return Smi::FromInt(EQUAL);
7100 if (isless(x, y)) return Smi::FromInt(LESS);
7101 return Smi::FromInt(GREATER);
7102}
7103
7104
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007105// Compare two Smis as if they were converted to strings and then
7106// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007107RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007108 NoHandleAllocation ha;
7109 ASSERT(args.length() == 2);
7110
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007111 // Extract the integer values from the Smis.
7112 CONVERT_CHECKED(Smi, x, args[0]);
7113 CONVERT_CHECKED(Smi, y, args[1]);
7114 int x_value = x->value();
7115 int y_value = y->value();
7116
7117 // If the integers are equal so are the string representations.
7118 if (x_value == y_value) return Smi::FromInt(EQUAL);
7119
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007120 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007121 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007122 if (x_value == 0 || y_value == 0)
7123 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007124
ager@chromium.org32912102009-01-16 10:38:43 +00007125 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007126 // smallest because the char code of '-' is less than the char code
7127 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007128
7129 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7130 // architectures using 32-bit Smis.
7131 uint32_t x_scaled = x_value;
7132 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007133 if (x_value < 0 || y_value < 0) {
7134 if (y_value >= 0) return Smi::FromInt(LESS);
7135 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007136 x_scaled = -x_value;
7137 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007138 }
7139
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007140 static const uint32_t kPowersOf10[] = {
7141 1, 10, 100, 1000, 10*1000, 100*1000,
7142 1000*1000, 10*1000*1000, 100*1000*1000,
7143 1000*1000*1000
7144 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007145
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007146 // If the integers have the same number of decimal digits they can be
7147 // compared directly as the numeric order is the same as the
7148 // lexicographic order. If one integer has fewer digits, it is scaled
7149 // by some power of 10 to have the same number of digits as the longer
7150 // integer. If the scaled integers are equal it means the shorter
7151 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007152
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007153 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7154 int x_log2 = IntegerLog2(x_scaled);
7155 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7156 x_log10 -= x_scaled < kPowersOf10[x_log10];
7157
7158 int y_log2 = IntegerLog2(y_scaled);
7159 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7160 y_log10 -= y_scaled < kPowersOf10[y_log10];
7161
7162 int tie = EQUAL;
7163
7164 if (x_log10 < y_log10) {
7165 // X has fewer digits. We would like to simply scale up X but that
7166 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7167 // be scaled up to 9_000_000_000. So we scale up by the next
7168 // smallest power and scale down Y to drop one digit. It is OK to
7169 // drop one digit from the longer integer since the final digit is
7170 // past the length of the shorter integer.
7171 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7172 y_scaled /= 10;
7173 tie = LESS;
7174 } else if (y_log10 < x_log10) {
7175 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7176 x_scaled /= 10;
7177 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007178 }
7179
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007180 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7181 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7182 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007183}
7184
7185
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007186static Object* StringInputBufferCompare(RuntimeState* state,
7187 String* x,
7188 String* y) {
7189 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7190 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007191 bufx.Reset(x);
7192 bufy.Reset(y);
7193 while (bufx.has_more() && bufy.has_more()) {
7194 int d = bufx.GetNext() - bufy.GetNext();
7195 if (d < 0) return Smi::FromInt(LESS);
7196 else if (d > 0) return Smi::FromInt(GREATER);
7197 }
7198
7199 // x is (non-trivial) prefix of y:
7200 if (bufy.has_more()) return Smi::FromInt(LESS);
7201 // y is prefix of x:
7202 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7203}
7204
7205
7206static Object* FlatStringCompare(String* x, String* y) {
7207 ASSERT(x->IsFlat());
7208 ASSERT(y->IsFlat());
7209 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7210 int prefix_length = x->length();
7211 if (y->length() < prefix_length) {
7212 prefix_length = y->length();
7213 equal_prefix_result = Smi::FromInt(GREATER);
7214 } else if (y->length() > prefix_length) {
7215 equal_prefix_result = Smi::FromInt(LESS);
7216 }
7217 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007218 String::FlatContent x_content = x->GetFlatContent();
7219 String::FlatContent y_content = y->GetFlatContent();
7220 if (x_content.IsAscii()) {
7221 Vector<const char> x_chars = x_content.ToAsciiVector();
7222 if (y_content.IsAscii()) {
7223 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007224 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007225 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007226 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007227 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7228 }
7229 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007230 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7231 if (y_content.IsAscii()) {
7232 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007233 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7234 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007235 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007236 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7237 }
7238 }
7239 Object* result;
7240 if (r == 0) {
7241 result = equal_prefix_result;
7242 } else {
7243 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7244 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007245 ASSERT(result ==
7246 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007247 return result;
7248}
7249
7250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007251RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007252 NoHandleAllocation ha;
7253 ASSERT(args.length() == 2);
7254
7255 CONVERT_CHECKED(String, x, args[0]);
7256 CONVERT_CHECKED(String, y, args[1]);
7257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007258 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007259
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007260 // A few fast case tests before we flatten.
7261 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007262 if (y->length() == 0) {
7263 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007264 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007265 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266 return Smi::FromInt(LESS);
7267 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007268
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007269 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007270 if (d < 0) return Smi::FromInt(LESS);
7271 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272
lrn@chromium.org303ada72010-10-27 09:33:13 +00007273 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007274 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007275 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7276 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007277 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007278 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007280
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007281 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007282 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283}
7284
7285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007286RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007287 NoHandleAllocation ha;
7288 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007289 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007291 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007292 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007293}
7294
7295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007296RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297 NoHandleAllocation ha;
7298 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007299 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007300
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007301 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007302 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303}
7304
7305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007306RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307 NoHandleAllocation ha;
7308 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007309 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007310
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007311 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007312 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313}
7314
7315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007316static const double kPiDividedBy4 = 0.78539816339744830962;
7317
7318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007319RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007320 NoHandleAllocation ha;
7321 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007323
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007324 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7325 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007326 double result;
7327 if (isinf(x) && isinf(y)) {
7328 // Make sure that the result in case of two infinite arguments
7329 // is a multiple of Pi / 4. The sign of the result is determined
7330 // by the first argument (x) and the sign of the second argument
7331 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007332 int multiplier = (x < 0) ? -1 : 1;
7333 if (y < 0) multiplier *= 3;
7334 result = multiplier * kPiDividedBy4;
7335 } else {
7336 result = atan2(x, y);
7337 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339}
7340
7341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007342RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007343 NoHandleAllocation ha;
7344 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007345 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007347 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007348 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349}
7350
7351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007352RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353 NoHandleAllocation ha;
7354 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007355 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007357 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007358 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007359}
7360
7361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007362RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363 NoHandleAllocation ha;
7364 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007365 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007367 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007368 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369}
7370
7371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007372RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373 NoHandleAllocation ha;
7374 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007375 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007377 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379}
7380
7381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007382RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383 NoHandleAllocation ha;
7384 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007385 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007387 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007388 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389}
7390
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007391// Slow version of Math.pow. We check for fast paths for special cases.
7392// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007393RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394 NoHandleAllocation ha;
7395 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007398 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007399
7400 // If the second argument is a smi, it is much faster to call the
7401 // custom powi() function than the generic pow().
7402 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007403 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007405 }
7406
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007407 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007408 int y_int = static_cast<int>(y);
7409 double result;
7410 if (y == y_int) {
7411 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7412 } else if (y == 0.5) {
7413 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7414 } else if (y == -0.5) {
7415 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7416 } else {
7417 result = power_double_double(x, y);
7418 }
7419 if (isnan(result)) return isolate->heap()->nan_value();
7420 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421}
7422
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007423// Fast version of Math.pow if we know that y is not an integer and y is not
7424// -0.5 or 0.5. Used as slow case from fullcodegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007425RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007426 NoHandleAllocation ha;
7427 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007428 isolate->counters()->math_pow()->Increment();
7429
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007430 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7431 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007432 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007433 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007434 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007435 double result = power_double_double(x, y);
7436 if (isnan(result)) return isolate->heap()->nan_value();
7437 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007438 }
7439}
7440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007442RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007443 NoHandleAllocation ha;
7444 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007445 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007446
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007447 if (!args[0]->IsHeapNumber()) {
7448 // Must be smi. Return the argument unchanged for all the other types
7449 // to make fuzz-natives test happy.
7450 return args[0];
7451 }
7452
7453 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7454
7455 double value = number->value();
7456 int exponent = number->get_exponent();
7457 int sign = number->get_sign();
7458
danno@chromium.org160a7b02011-04-18 15:51:38 +00007459 if (exponent < -1) {
7460 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7461 if (sign) return isolate->heap()->minus_zero_value();
7462 return Smi::FromInt(0);
7463 }
7464
7465 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7466 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7467 // agument holds for 32-bit smis).
7468 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007469 return Smi::FromInt(static_cast<int>(value + 0.5));
7470 }
7471
7472 // If the magnitude is big enough, there's no place for fraction part. If we
7473 // try to add 0.5 to this number, 1.0 will be added instead.
7474 if (exponent >= 52) {
7475 return number;
7476 }
7477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007478 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007479
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007480 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007481 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007482}
7483
7484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007485RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007486 NoHandleAllocation ha;
7487 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007488 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007489
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007490 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007491 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007492}
7493
7494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007495RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007496 NoHandleAllocation ha;
7497 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007498 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007500 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007501 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007502}
7503
7504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007505RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007506 NoHandleAllocation ha;
7507 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007508 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007509
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007510 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512}
7513
7514
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007515static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007516 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7517 181, 212, 243, 273, 304, 334};
7518 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7519 182, 213, 244, 274, 305, 335};
7520
7521 year += month / 12;
7522 month %= 12;
7523 if (month < 0) {
7524 year--;
7525 month += 12;
7526 }
7527
7528 ASSERT(month >= 0);
7529 ASSERT(month < 12);
7530
7531 // year_delta is an arbitrary number such that:
7532 // a) year_delta = -1 (mod 400)
7533 // b) year + year_delta > 0 for years in the range defined by
7534 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7535 // Jan 1 1970. This is required so that we don't run into integer
7536 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007537 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007538 // operations.
7539 static const int year_delta = 399999;
7540 static const int base_day = 365 * (1970 + year_delta) +
7541 (1970 + year_delta) / 4 -
7542 (1970 + year_delta) / 100 +
7543 (1970 + year_delta) / 400;
7544
7545 int year1 = year + year_delta;
7546 int day_from_year = 365 * year1 +
7547 year1 / 4 -
7548 year1 / 100 +
7549 year1 / 400 -
7550 base_day;
7551
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007552 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7553 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007554 }
7555
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007556 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007557}
7558
7559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007560RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007561 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007562 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007563
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007564 CONVERT_SMI_ARG_CHECKED(year, 0);
7565 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007566
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007567 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007568}
7569
7570
7571static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7572static const int kDaysIn4Years = 4 * 365 + 1;
7573static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7574static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7575static const int kDays1970to2000 = 30 * 365 + 7;
7576static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7577 kDays1970to2000;
7578static const int kYearsOffset = 400000;
7579
7580static const char kDayInYear[] = {
7581 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7582 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7583 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7584 22, 23, 24, 25, 26, 27, 28,
7585 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7586 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7587 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7588 22, 23, 24, 25, 26, 27, 28, 29, 30,
7589 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7590 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7591 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7592 22, 23, 24, 25, 26, 27, 28, 29, 30,
7593 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7594 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7595 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7596 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7597 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7598 22, 23, 24, 25, 26, 27, 28, 29, 30,
7599 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7600 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7601 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7602 22, 23, 24, 25, 26, 27, 28, 29, 30,
7603 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7604 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7605
7606 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7607 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7608 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7609 22, 23, 24, 25, 26, 27, 28,
7610 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7611 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7612 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7613 22, 23, 24, 25, 26, 27, 28, 29, 30,
7614 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7615 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7616 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7617 22, 23, 24, 25, 26, 27, 28, 29, 30,
7618 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7619 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7620 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7621 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7622 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7623 22, 23, 24, 25, 26, 27, 28, 29, 30,
7624 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7625 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7626 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7627 22, 23, 24, 25, 26, 27, 28, 29, 30,
7628 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7629 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7630
7631 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7632 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7633 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7634 22, 23, 24, 25, 26, 27, 28, 29,
7635 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7636 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7637 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7638 22, 23, 24, 25, 26, 27, 28, 29, 30,
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7641 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7642 22, 23, 24, 25, 26, 27, 28, 29, 30,
7643 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7644 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7647 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7648 22, 23, 24, 25, 26, 27, 28, 29, 30,
7649 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7650 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7651 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7652 22, 23, 24, 25, 26, 27, 28, 29, 30,
7653 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7654 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7655
7656 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7657 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7658 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7659 22, 23, 24, 25, 26, 27, 28,
7660 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7661 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7662 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7663 22, 23, 24, 25, 26, 27, 28, 29, 30,
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7666 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7667 22, 23, 24, 25, 26, 27, 28, 29, 30,
7668 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7669 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7672 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7673 22, 23, 24, 25, 26, 27, 28, 29, 30,
7674 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7675 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7676 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7677 22, 23, 24, 25, 26, 27, 28, 29, 30,
7678 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7679 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7680
7681static const char kMonthInYear[] = {
7682 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7683 0, 0, 0, 0, 0, 0,
7684 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7685 1, 1, 1,
7686 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7687 2, 2, 2, 2, 2, 2,
7688 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7689 3, 3, 3, 3, 3,
7690 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7691 4, 4, 4, 4, 4, 4,
7692 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7693 5, 5, 5, 5, 5,
7694 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7695 6, 6, 6, 6, 6, 6,
7696 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7697 7, 7, 7, 7, 7, 7,
7698 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7699 8, 8, 8, 8, 8,
7700 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7701 9, 9, 9, 9, 9, 9,
7702 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7703 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7704 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7705 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7706
7707 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7708 0, 0, 0, 0, 0, 0,
7709 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7710 1, 1, 1,
7711 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7712 2, 2, 2, 2, 2, 2,
7713 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7714 3, 3, 3, 3, 3,
7715 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7716 4, 4, 4, 4, 4, 4,
7717 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7718 5, 5, 5, 5, 5,
7719 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7720 6, 6, 6, 6, 6, 6,
7721 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7722 7, 7, 7, 7, 7, 7,
7723 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7724 8, 8, 8, 8, 8,
7725 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7726 9, 9, 9, 9, 9, 9,
7727 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7728 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7729 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7730 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7731
7732 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7733 0, 0, 0, 0, 0, 0,
7734 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7735 1, 1, 1, 1,
7736 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7737 2, 2, 2, 2, 2, 2,
7738 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7739 3, 3, 3, 3, 3,
7740 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7741 4, 4, 4, 4, 4, 4,
7742 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7743 5, 5, 5, 5, 5,
7744 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7745 6, 6, 6, 6, 6, 6,
7746 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7747 7, 7, 7, 7, 7, 7,
7748 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7749 8, 8, 8, 8, 8,
7750 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7751 9, 9, 9, 9, 9, 9,
7752 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7753 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7754 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7755 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7756
7757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7758 0, 0, 0, 0, 0, 0,
7759 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7760 1, 1, 1,
7761 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7762 2, 2, 2, 2, 2, 2,
7763 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7764 3, 3, 3, 3, 3,
7765 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7766 4, 4, 4, 4, 4, 4,
7767 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7768 5, 5, 5, 5, 5,
7769 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7770 6, 6, 6, 6, 6, 6,
7771 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7772 7, 7, 7, 7, 7, 7,
7773 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7774 8, 8, 8, 8, 8,
7775 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7776 9, 9, 9, 9, 9, 9,
7777 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7778 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7779 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7780 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7781
7782
7783// This function works for dates from 1970 to 2099.
7784static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007785 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007786#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007787 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007788#endif
7789
7790 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7791 date %= kDaysIn4Years;
7792
7793 month = kMonthInYear[date];
7794 day = kDayInYear[date];
7795
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007796 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007797}
7798
7799
7800static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007801 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007802#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007803 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007804#endif
7805
7806 date += kDaysOffset;
7807 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7808 date %= kDaysIn400Years;
7809
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007810 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007811
7812 date--;
7813 int yd1 = date / kDaysIn100Years;
7814 date %= kDaysIn100Years;
7815 year += 100 * yd1;
7816
7817 date++;
7818 int yd2 = date / kDaysIn4Years;
7819 date %= kDaysIn4Years;
7820 year += 4 * yd2;
7821
7822 date--;
7823 int yd3 = date / 365;
7824 date %= 365;
7825 year += yd3;
7826
7827 bool is_leap = (!yd1 || yd2) && !yd3;
7828
7829 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007830 ASSERT(is_leap || (date >= 0));
7831 ASSERT((date < 365) || (is_leap && (date < 366)));
7832 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007833 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7834 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007835
7836 if (is_leap) {
7837 day = kDayInYear[2*365 + 1 + date];
7838 month = kMonthInYear[2*365 + 1 + date];
7839 } else {
7840 day = kDayInYear[date];
7841 month = kMonthInYear[date];
7842 }
7843
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007844 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007845}
7846
7847
7848static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007849 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007850 if (date >= 0 && date < 32 * kDaysIn4Years) {
7851 DateYMDFromTimeAfter1970(date, year, month, day);
7852 } else {
7853 DateYMDFromTimeSlow(date, year, month, day);
7854 }
7855}
7856
7857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007858RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007859 NoHandleAllocation ha;
7860 ASSERT(args.length() == 2);
7861
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007862 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007863 CONVERT_CHECKED(JSArray, res_array, args[1]);
7864
7865 int year, month, day;
7866 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7867
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007868 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7869 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007870 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007871
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007872 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7873 if (maybe->IsFailure()) return maybe;
7874 FixedArray* elms = FixedArray::cast(res_array->elements());
7875 elms->set(0, Smi::FromInt(year));
7876 elms->set(1, Smi::FromInt(month));
7877 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007879 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007880}
7881
7882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007883RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007884 HandleScope scope(isolate);
7885 ASSERT(args.length() == 3);
7886
7887 Handle<JSFunction> callee = args.at<JSFunction>(0);
7888 Object** parameters = reinterpret_cast<Object**>(args[1]);
7889 const int argument_count = Smi::cast(args[2])->value();
7890
7891 Handle<JSObject> result =
7892 isolate->factory()->NewArgumentsObject(callee, argument_count);
7893 // Allocate the elements if needed.
7894 int parameter_count = callee->shared()->formal_parameter_count();
7895 if (argument_count > 0) {
7896 if (parameter_count > 0) {
7897 int mapped_count = Min(argument_count, parameter_count);
7898 Handle<FixedArray> parameter_map =
7899 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7900 parameter_map->set_map(
7901 isolate->heap()->non_strict_arguments_elements_map());
7902
7903 Handle<Map> old_map(result->map());
7904 Handle<Map> new_map =
7905 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007906 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007907
7908 result->set_map(*new_map);
7909 result->set_elements(*parameter_map);
7910
7911 // Store the context and the arguments array at the beginning of the
7912 // parameter map.
7913 Handle<Context> context(isolate->context());
7914 Handle<FixedArray> arguments =
7915 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7916 parameter_map->set(0, *context);
7917 parameter_map->set(1, *arguments);
7918
7919 // Loop over the actual parameters backwards.
7920 int index = argument_count - 1;
7921 while (index >= mapped_count) {
7922 // These go directly in the arguments array and have no
7923 // corresponding slot in the parameter map.
7924 arguments->set(index, *(parameters - index - 1));
7925 --index;
7926 }
7927
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007928 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007929 while (index >= 0) {
7930 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007931 Handle<String> name(scope_info->ParameterName(index));
7932 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007933 bool duplicate = false;
7934 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007935 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007936 duplicate = true;
7937 break;
7938 }
7939 }
7940
7941 if (duplicate) {
7942 // This goes directly in the arguments array with a hole in the
7943 // parameter map.
7944 arguments->set(index, *(parameters - index - 1));
7945 parameter_map->set_the_hole(index + 2);
7946 } else {
7947 // The context index goes in the parameter map with a hole in the
7948 // arguments array.
7949 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007950 for (int j = 0; j < context_local_count; ++j) {
7951 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007952 context_index = j;
7953 break;
7954 }
7955 }
7956 ASSERT(context_index >= 0);
7957 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007958 parameter_map->set(index + 2, Smi::FromInt(
7959 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007960 }
7961
7962 --index;
7963 }
7964 } else {
7965 // If there is no aliasing, the arguments object elements are not
7966 // special in any way.
7967 Handle<FixedArray> elements =
7968 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7969 result->set_elements(*elements);
7970 for (int i = 0; i < argument_count; ++i) {
7971 elements->set(i, *(parameters - i - 1));
7972 }
7973 }
7974 }
7975 return *result;
7976}
7977
7978
7979RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007980 NoHandleAllocation ha;
7981 ASSERT(args.length() == 3);
7982
7983 JSFunction* callee = JSFunction::cast(args[0]);
7984 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007985 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007986
lrn@chromium.org303ada72010-10-27 09:33:13 +00007987 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007988 { MaybeObject* maybe_result =
7989 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007990 if (!maybe_result->ToObject(&result)) return maybe_result;
7991 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007992 // Allocate the elements if needed.
7993 if (length > 0) {
7994 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007995 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007996 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007997 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7998 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007999
8000 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008001 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008002 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008003 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008004
8005 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008006 for (int i = 0; i < length; i++) {
8007 array->set(i, *--parameters, mode);
8008 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008009 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008010 }
8011 return result;
8012}
8013
8014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008015RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008016 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008017 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008018 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008019 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008020 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008021
whesse@chromium.org7b260152011-06-20 15:33:18 +00008022 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008023 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008024 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008026 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8027 context,
8028 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029 return *result;
8030}
8031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008032
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008033// Find the arguments of the JavaScript function invocation that called
8034// into C++ code. Collect these in a newly allocated array of handles (possibly
8035// prefixed by a number of empty handles).
8036static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8037 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008038 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008039 // Find frame containing arguments passed to the caller.
8040 JavaScriptFrameIterator it;
8041 JavaScriptFrame* frame = it.frame();
8042 List<JSFunction*> functions(2);
8043 frame->GetFunctions(&functions);
8044 if (functions.length() > 1) {
8045 int inlined_frame_index = functions.length() - 1;
8046 JSFunction* inlined_function = functions[inlined_frame_index];
8047 int args_count = inlined_function->shared()->formal_parameter_count();
8048 ScopedVector<SlotRef> args_slots(args_count);
8049 SlotRef::ComputeSlotMappingForArguments(frame,
8050 inlined_frame_index,
8051 &args_slots);
8052
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008053 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008054 SmartArrayPointer<Handle<Object> > param_data(
8055 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008056 for (int i = 0; i < args_count; i++) {
8057 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008058 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008059 }
8060 return param_data;
8061 } else {
8062 it.AdvanceToArgumentsFrame();
8063 frame = it.frame();
8064 int args_count = frame->ComputeParametersCount();
8065
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008066 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008067 SmartArrayPointer<Handle<Object> > param_data(
8068 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008069 for (int i = 0; i < args_count; i++) {
8070 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008071 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008072 }
8073 return param_data;
8074 }
8075}
8076
8077
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008078RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8079 HandleScope scope(isolate);
8080 ASSERT(args.length() == 4);
8081 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8082 RUNTIME_ASSERT(args[3]->IsNumber());
8083 Handle<Object> bindee = args.at<Object>(1);
8084
8085 // TODO(lrn): Create bound function in C++ code from premade shared info.
8086 bound_function->shared()->set_bound(true);
8087 // Get all arguments of calling function (Function.prototype.bind).
8088 int argc = 0;
8089 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8090 // Don't count the this-arg.
8091 if (argc > 0) {
8092 ASSERT(*arguments[0] == args[2]);
8093 argc--;
8094 } else {
8095 ASSERT(args[2]->IsUndefined());
8096 }
8097 // Initialize array of bindings (function, this, and any existing arguments
8098 // if the function was already bound).
8099 Handle<FixedArray> new_bindings;
8100 int i;
8101 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8102 Handle<FixedArray> old_bindings(
8103 JSFunction::cast(*bindee)->function_bindings());
8104 new_bindings =
8105 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8106 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8107 i = 0;
8108 for (int n = old_bindings->length(); i < n; i++) {
8109 new_bindings->set(i, old_bindings->get(i));
8110 }
8111 } else {
8112 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8113 new_bindings = isolate->factory()->NewFixedArray(array_size);
8114 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8115 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8116 i = 2;
8117 }
8118 // Copy arguments, skipping the first which is "this_arg".
8119 for (int j = 0; j < argc; j++, i++) {
8120 new_bindings->set(i, *arguments[j + 1]);
8121 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008122 new_bindings->set_map_no_write_barrier(
8123 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008124 bound_function->set_function_bindings(*new_bindings);
8125
8126 // Update length.
8127 Handle<String> length_symbol = isolate->factory()->length_symbol();
8128 Handle<Object> new_length(args.at<Object>(3));
8129 PropertyAttributes attr =
8130 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8131 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8132 return *bound_function;
8133}
8134
8135
8136RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8137 HandleScope handles(isolate);
8138 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008139 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008140 if (callable->IsJSFunction()) {
8141 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8142 if (function->shared()->bound()) {
8143 Handle<FixedArray> bindings(function->function_bindings());
8144 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8145 return *isolate->factory()->NewJSArrayWithElements(bindings);
8146 }
8147 }
8148 return isolate->heap()->undefined_value();
8149}
8150
8151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008152RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008153 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008154 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008155 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008156 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008157 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008158
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008159 // The argument is a bound function. Extract its bound arguments
8160 // and callable.
8161 Handle<FixedArray> bound_args =
8162 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8163 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8164 Handle<Object> bound_function(
8165 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8166 ASSERT(!bound_function->IsJSFunction() ||
8167 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008169 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008170 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008171 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008172 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008173 param_data[i] = Handle<Object>(bound_args->get(
8174 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008175 }
8176
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008177 if (!bound_function->IsJSFunction()) {
8178 bool exception_thrown;
8179 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8180 &exception_thrown);
8181 if (exception_thrown) return Failure::Exception();
8182 }
8183 ASSERT(bound_function->IsJSFunction());
8184
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008185 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008186 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008187 Execution::New(Handle<JSFunction>::cast(bound_function),
8188 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008189 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008190 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008191 }
8192 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008193 return *result;
8194}
8195
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008196
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008197static void TrySettingInlineConstructStub(Isolate* isolate,
8198 Handle<JSFunction> function) {
8199 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008200 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008201 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008202 }
8203 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008204 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008205 Handle<Code> code = compiler.CompileConstructStub(function);
8206 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008207 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008208}
8209
8210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008211RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008213 ASSERT(args.length() == 1);
8214
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008215 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008216
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008217 // If the constructor isn't a proper function we throw a type error.
8218 if (!constructor->IsJSFunction()) {
8219 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8220 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008221 isolate->factory()->NewTypeError("not_constructor", arguments);
8222 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008223 }
8224
8225 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008226
8227 // If function should not have prototype, construction is not allowed. In this
8228 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008229 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008230 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8231 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008232 isolate->factory()->NewTypeError("not_constructor", arguments);
8233 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008234 }
8235
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008236#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008237 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008238 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008239 if (debug->StepInActive()) {
8240 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008241 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008242#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008243
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008244 if (function->has_initial_map()) {
8245 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246 // The 'Function' function ignores the receiver object when
8247 // called using 'new' and creates a new JSFunction object that
8248 // is returned. The receiver object is only used for error
8249 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008250 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008251 // allocate JSFunctions since it does not properly initialize
8252 // the shared part of the function. Since the receiver is
8253 // ignored anyway, we use the global object as the receiver
8254 // instead of a new JSFunction object. This way, errors are
8255 // reported the same way whether or not 'Function' is called
8256 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008257 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008259 }
8260
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008261 // The function should be compiled for the optimization hints to be
8262 // available. We cannot use EnsureCompiled because that forces a
8263 // compilation through the shared function info which makes it
8264 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008265 if (!function->is_compiled()) {
8266 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8267 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008268
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008269 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008270 if (!function->has_initial_map() &&
8271 shared->IsInobjectSlackTrackingInProgress()) {
8272 // The tracking is already in progress for another function. We can only
8273 // track one initial_map at a time, so we force the completion before the
8274 // function is called as a constructor for the first time.
8275 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008276 }
8277
8278 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008279 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8280 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008281 // Delay setting the stub if inobject slack tracking is in progress.
8282 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008283 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008284 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008286 isolate->counters()->constructed_objects()->Increment();
8287 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008288
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008289 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290}
8291
8292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008293RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008294 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008295 ASSERT(args.length() == 1);
8296
8297 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8298 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008299 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008301 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008302}
8303
8304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008305RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008306 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008307 ASSERT(args.length() == 1);
8308
8309 Handle<JSFunction> function = args.at<JSFunction>(0);
8310#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008311 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008312 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008313 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008314 PrintF("]\n");
8315 }
8316#endif
8317
lrn@chromium.org34e60782011-09-15 07:25:40 +00008318 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008320 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 return Failure::Exception();
8322 }
8323
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008324 // All done. Return the compiled code.
8325 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326 return function->code();
8327}
8328
8329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008330RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008331 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008332 ASSERT(args.length() == 1);
8333 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008334
8335 // If the function is not compiled ignore the lazy
8336 // recompilation. This can happen if the debugger is activated and
8337 // the function is returned to the not compiled state.
8338 if (!function->shared()->is_compiled()) {
8339 function->ReplaceCode(function->shared()->code());
8340 return function->code();
8341 }
8342
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008343 // If the function is not optimizable or debugger is active continue using the
8344 // code from the full compiler.
8345 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008346 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008347 if (FLAG_trace_opt) {
8348 PrintF("[failed to optimize ");
8349 function->PrintName();
8350 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8351 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008352 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008353 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008354 function->ReplaceCode(function->shared()->code());
8355 return function->code();
8356 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008357 if (JSFunction::CompileOptimized(function,
8358 AstNode::kNoNumber,
8359 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008360 return function->code();
8361 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008362 if (FLAG_trace_opt) {
8363 PrintF("[failed to optimize ");
8364 function->PrintName();
8365 PrintF(": optimized compilation failed]\n");
8366 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008367 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008368 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008369}
8370
8371
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008372class ActivationsFinder : public ThreadVisitor {
8373 public:
8374 explicit ActivationsFinder(JSFunction* function)
8375 : function_(function), has_activations_(false) {}
8376
8377 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8378 if (has_activations_) return;
8379
8380 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8381 JavaScriptFrame* frame = it.frame();
8382 if (frame->is_optimized() && frame->function() == function_) {
8383 has_activations_ = true;
8384 return;
8385 }
8386 }
8387 }
8388
8389 bool has_activations() { return has_activations_; }
8390
8391 private:
8392 JSFunction* function_;
8393 bool has_activations_;
8394};
8395
8396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008397RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008398 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008399 ASSERT(args.length() == 1);
8400 RUNTIME_ASSERT(args[0]->IsSmi());
8401 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008402 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008403 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8404 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008405 int frames = deoptimizer->output_count();
8406
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008407 deoptimizer->MaterializeHeapNumbers();
8408 delete deoptimizer;
8409
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008410 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008411 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008412 for (int i = 0; i < frames - 1; i++) it.Advance();
8413 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008414
8415 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008416 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008417 Handle<Object> arguments;
8418 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008420 if (arguments.is_null()) {
8421 // FunctionGetArguments can't throw an exception, so cast away the
8422 // doubt with an assert.
8423 arguments = Handle<Object>(
8424 Accessors::FunctionGetArguments(*function,
8425 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008426 ASSERT(*arguments != isolate->heap()->null_value());
8427 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008428 }
8429 frame->SetExpression(i, *arguments);
8430 }
8431 }
8432
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008433 if (type == Deoptimizer::EAGER) {
8434 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008435 }
8436
8437 // Avoid doing too much work when running with --always-opt and keep
8438 // the optimized code around.
8439 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008441 }
8442
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008443 // Find other optimized activations of the function.
8444 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008445 while (!it.done()) {
8446 JavaScriptFrame* frame = it.frame();
8447 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008448 has_other_activations = true;
8449 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008450 }
8451 it.Advance();
8452 }
8453
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008454 if (!has_other_activations) {
8455 ActivationsFinder activations_finder(*function);
8456 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8457 has_other_activations = activations_finder.has_activations();
8458 }
8459
8460 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008461 if (FLAG_trace_deopt) {
8462 PrintF("[removing optimized code for: ");
8463 function->PrintName();
8464 PrintF("]\n");
8465 }
8466 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008467 } else {
8468 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008469 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008470 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008471}
8472
8473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008474RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008475 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008476 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008477 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008478}
8479
8480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008481RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008482 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008483 ASSERT(args.length() == 1);
8484 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008485 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008486
8487 Deoptimizer::DeoptimizeFunction(*function);
8488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008490}
8491
8492
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008493RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8494#if defined(USE_SIMULATOR)
8495 return isolate->heap()->true_value();
8496#else
8497 return isolate->heap()->false_value();
8498#endif
8499}
8500
8501
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008502RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8503 HandleScope scope(isolate);
8504 ASSERT(args.length() == 1);
8505 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8506 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8507 function->MarkForLazyRecompilation();
8508 return isolate->heap()->undefined_value();
8509}
8510
8511
lrn@chromium.org1c092762011-05-09 09:42:16 +00008512RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8513 HandleScope scope(isolate);
8514 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008515 // The least significant bit (after untagging) indicates whether the
8516 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008517 if (!V8::UseCrankshaft()) {
8518 return Smi::FromInt(4); // 4 == "never".
8519 }
8520 if (FLAG_always_opt) {
8521 return Smi::FromInt(3); // 3 == "always".
8522 }
8523 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8524 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8525 : Smi::FromInt(2); // 2 == "no".
8526}
8527
8528
8529RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8530 HandleScope scope(isolate);
8531 ASSERT(args.length() == 1);
8532 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8533 return Smi::FromInt(function->shared()->opt_count());
8534}
8535
8536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008537RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008538 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008539 ASSERT(args.length() == 1);
8540 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8541
8542 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008543 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008544
8545 // We have hit a back edge in an unoptimized frame for a function that was
8546 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008547 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008548 // Keep track of whether we've succeeded in optimizing.
8549 bool succeeded = unoptimized->optimizable();
8550 if (succeeded) {
8551 // If we are trying to do OSR when there are already optimized
8552 // activations of the function, it means (a) the function is directly or
8553 // indirectly recursive and (b) an optimized invocation has been
8554 // deoptimized so that we are currently in an unoptimized activation.
8555 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008556 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008557 while (succeeded && !it.done()) {
8558 JavaScriptFrame* frame = it.frame();
8559 succeeded = !frame->is_optimized() || frame->function() != *function;
8560 it.Advance();
8561 }
8562 }
8563
8564 int ast_id = AstNode::kNoNumber;
8565 if (succeeded) {
8566 // The top JS function is this one, the PC is somewhere in the
8567 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008568 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008569 JavaScriptFrame* frame = it.frame();
8570 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008571 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008572 ASSERT(unoptimized->contains(frame->pc()));
8573
8574 // Use linear search of the unoptimized code's stack check table to find
8575 // the AST id matching the PC.
8576 Address start = unoptimized->instruction_start();
8577 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008578 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008579 uint32_t table_length = Memory::uint32_at(table_cursor);
8580 table_cursor += kIntSize;
8581 for (unsigned i = 0; i < table_length; ++i) {
8582 // Table entries are (AST id, pc offset) pairs.
8583 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8584 if (pc_offset == target_pc_offset) {
8585 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8586 break;
8587 }
8588 table_cursor += 2 * kIntSize;
8589 }
8590 ASSERT(ast_id != AstNode::kNoNumber);
8591 if (FLAG_trace_osr) {
8592 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8593 function->PrintName();
8594 PrintF("]\n");
8595 }
8596
8597 // Try to compile the optimized code. A true return value from
8598 // CompileOptimized means that compilation succeeded, not necessarily
8599 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008600 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008601 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008602 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8603 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008604 if (data->OsrPcOffset()->value() >= 0) {
8605 if (FLAG_trace_osr) {
8606 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008607 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008608 }
8609 ASSERT(data->OsrAstId()->value() == ast_id);
8610 } else {
8611 // We may never generate the desired OSR entry if we emit an
8612 // early deoptimize.
8613 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008614 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008615 } else {
8616 succeeded = false;
8617 }
8618 }
8619
8620 // Revert to the original stack checks in the original unoptimized code.
8621 if (FLAG_trace_osr) {
8622 PrintF("[restoring original stack checks in ");
8623 function->PrintName();
8624 PrintF("]\n");
8625 }
8626 StackCheckStub check_stub;
8627 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008628 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008629 Deoptimizer::RevertStackCheckCode(*unoptimized,
8630 *check_code,
8631 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008632
8633 // Allow OSR only at nesting level zero again.
8634 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8635
8636 // If the optimization attempt succeeded, return the AST id tagged as a
8637 // smi. This tells the builtin that we need to translate the unoptimized
8638 // frame to an optimized one.
8639 if (succeeded) {
8640 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8641 return Smi::FromInt(ast_id);
8642 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008643 if (function->IsMarkedForLazyRecompilation()) {
8644 function->ReplaceCode(function->shared()->code());
8645 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008646 return Smi::FromInt(-1);
8647 }
8648}
8649
8650
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008651RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8652 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8653 return isolate->heap()->undefined_value();
8654}
8655
8656
danno@chromium.orgc612e022011-11-10 11:38:15 +00008657RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8658 HandleScope scope(isolate);
8659 ASSERT(args.length() >= 2);
8660 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8661 Object* receiver = args[0];
8662 int argc = args.length() - 2;
8663
8664 // If there are too many arguments, allocate argv via malloc.
8665 const int argv_small_size = 10;
8666 Handle<Object> argv_small_buffer[argv_small_size];
8667 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8668 Handle<Object>* argv = argv_small_buffer;
8669 if (argc > argv_small_size) {
8670 argv = new Handle<Object>[argc];
8671 if (argv == NULL) return isolate->StackOverflow();
8672 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8673 }
8674
8675 for (int i = 0; i < argc; ++i) {
8676 MaybeObject* maybe = args[1 + i];
8677 Object* object;
8678 if (!maybe->To<Object>(&object)) return maybe;
8679 argv[i] = Handle<Object>(object);
8680 }
8681
8682 bool threw;
8683 Handle<JSReceiver> hfun(fun);
8684 Handle<Object> hreceiver(receiver);
8685 Handle<Object> result =
8686 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8687
8688 if (threw) return Failure::Exception();
8689 return *result;
8690}
8691
8692
lrn@chromium.org34e60782011-09-15 07:25:40 +00008693RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8694 HandleScope scope(isolate);
8695 ASSERT(args.length() == 5);
8696 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8697 Object* receiver = args[1];
8698 CONVERT_CHECKED(JSObject, arguments, args[2]);
8699 CONVERT_CHECKED(Smi, shift, args[3]);
8700 CONVERT_CHECKED(Smi, arity, args[4]);
8701
8702 int offset = shift->value();
8703 int argc = arity->value();
8704 ASSERT(offset >= 0);
8705 ASSERT(argc >= 0);
8706
8707 // If there are too many arguments, allocate argv via malloc.
8708 const int argv_small_size = 10;
8709 Handle<Object> argv_small_buffer[argv_small_size];
8710 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8711 Handle<Object>* argv = argv_small_buffer;
8712 if (argc > argv_small_size) {
8713 argv = new Handle<Object>[argc];
8714 if (argv == NULL) return isolate->StackOverflow();
8715 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8716 }
8717
8718 for (int i = 0; i < argc; ++i) {
8719 MaybeObject* maybe = arguments->GetElement(offset + i);
8720 Object* object;
8721 if (!maybe->To<Object>(&object)) return maybe;
8722 argv[i] = Handle<Object>(object);
8723 }
8724
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008725 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008726 Handle<JSReceiver> hfun(fun);
8727 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008728 Handle<Object> result =
8729 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008730
8731 if (threw) return Failure::Exception();
8732 return *result;
8733}
8734
8735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008736RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008737 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008738 ASSERT(args.length() == 1);
8739 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8740 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8741}
8742
8743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008744RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008745 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008746 ASSERT(args.length() == 1);
8747 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8748 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8749}
8750
8751
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008752RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008753 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008754 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008755
kasper.lund7276f142008-07-30 08:49:36 +00008756 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008757 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008758 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008759 { MaybeObject* maybe_result =
8760 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008761 if (!maybe_result->ToObject(&result)) return maybe_result;
8762 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008764 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008765
kasper.lund7276f142008-07-30 08:49:36 +00008766 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008767}
8768
lrn@chromium.org303ada72010-10-27 09:33:13 +00008769
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008770RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8771 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008772 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008773 JSObject* extension_object;
8774 if (args[0]->IsJSObject()) {
8775 extension_object = JSObject::cast(args[0]);
8776 } else {
8777 // Convert the object to a proper JavaScript object.
8778 MaybeObject* maybe_js_object = args[0]->ToObject();
8779 if (!maybe_js_object->To(&extension_object)) {
8780 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8781 HandleScope scope(isolate);
8782 Handle<Object> handle = args.at<Object>(0);
8783 Handle<Object> result =
8784 isolate->factory()->NewTypeError("with_expression",
8785 HandleVector(&handle, 1));
8786 return isolate->Throw(*result);
8787 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008788 return maybe_js_object;
8789 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790 }
8791 }
8792
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008793 JSFunction* function;
8794 if (args[1]->IsSmi()) {
8795 // A smi sentinel indicates a context nested inside global code rather
8796 // than some function. There is a canonical empty function that can be
8797 // gotten from the global context.
8798 function = isolate->context()->global_context()->closure();
8799 } else {
8800 function = JSFunction::cast(args[1]);
8801 }
8802
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008803 Context* context;
8804 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008805 isolate->heap()->AllocateWithContext(function,
8806 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008807 extension_object);
8808 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008810 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008811}
8812
8813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008814RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008815 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008816 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008817 String* name = String::cast(args[0]);
8818 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008819 JSFunction* function;
8820 if (args[2]->IsSmi()) {
8821 // A smi sentinel indicates a context nested inside global code rather
8822 // than some function. There is a canonical empty function that can be
8823 // gotten from the global context.
8824 function = isolate->context()->global_context()->closure();
8825 } else {
8826 function = JSFunction::cast(args[2]);
8827 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008828 Context* context;
8829 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008830 isolate->heap()->AllocateCatchContext(function,
8831 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008832 name,
8833 thrown_object);
8834 if (!maybe_context->To(&context)) return maybe_context;
8835 isolate->set_context(context);
8836 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008837}
8838
8839
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008840RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8841 NoHandleAllocation ha;
8842 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008843 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008844 JSFunction* function;
8845 if (args[1]->IsSmi()) {
8846 // A smi sentinel indicates a context nested inside global code rather
8847 // than some function. There is a canonical empty function that can be
8848 // gotten from the global context.
8849 function = isolate->context()->global_context()->closure();
8850 } else {
8851 function = JSFunction::cast(args[1]);
8852 }
8853 Context* context;
8854 MaybeObject* maybe_context =
8855 isolate->heap()->AllocateBlockContext(function,
8856 isolate->context(),
8857 scope_info);
8858 if (!maybe_context->To(&context)) return maybe_context;
8859 isolate->set_context(context);
8860 return context;
8861}
8862
8863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008864RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866 ASSERT(args.length() == 2);
8867
8868 CONVERT_ARG_CHECKED(Context, context, 0);
8869 CONVERT_ARG_CHECKED(String, name, 1);
8870
8871 int index;
8872 PropertyAttributes attributes;
8873 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008874 BindingFlags binding_flags;
8875 Handle<Object> holder = context->Lookup(name,
8876 flags,
8877 &index,
8878 &attributes,
8879 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008881 // If the slot was not found the result is true.
8882 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008883 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884 }
8885
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008886 // If the slot was found in a context, it should be DONT_DELETE.
8887 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008888 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008889 }
8890
8891 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008892 // the global object, or the subject of a with. Try to delete it
8893 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008894 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008895 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896}
8897
8898
ager@chromium.orga1645e22009-09-09 19:27:10 +00008899// A mechanism to return a pair of Object pointers in registers (if possible).
8900// How this is achieved is calling convention-dependent.
8901// All currently supported x86 compiles uses calling conventions that are cdecl
8902// variants where a 64-bit value is returned in two 32-bit registers
8903// (edx:eax on ia32, r1:r0 on ARM).
8904// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8905// In Win64 calling convention, a struct of two pointers is returned in memory,
8906// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008907#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008908struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008909 MaybeObject* x;
8910 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008911};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008912
lrn@chromium.org303ada72010-10-27 09:33:13 +00008913static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008914 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008915 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8916 // In Win64 they are assigned to a hidden first argument.
8917 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008918}
8919#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008920typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008921static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008923 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008924}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008925#endif
8926
8927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008928static inline MaybeObject* Unhole(Heap* heap,
8929 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008930 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008931 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8932 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008933 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934}
8935
8936
danno@chromium.org40cb8782011-05-25 07:58:50 +00008937static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8938 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008939 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008940 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008941 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008942 JSFunction* context_extension_function =
8943 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008944 // If the holder isn't a context extension object, we just return it
8945 // as the receiver. This allows arguments objects to be used as
8946 // receivers, but only if they are put in the context scope chain
8947 // explicitly via a with-statement.
8948 Object* constructor = holder->map()->constructor();
8949 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008950 // Fall back to using the global object as the implicit receiver if
8951 // the property turns out to be a local variable allocated in a
8952 // context extension object - introduced via eval. Implicit global
8953 // receivers are indicated with the hole value.
8954 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008955}
8956
8957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008958static ObjectPair LoadContextSlotHelper(Arguments args,
8959 Isolate* isolate,
8960 bool throw_error) {
8961 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008962 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008963
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008964 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008965 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008966 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008967 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008968 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969
8970 int index;
8971 PropertyAttributes attributes;
8972 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008973 BindingFlags binding_flags;
8974 Handle<Object> holder = context->Lookup(name,
8975 flags,
8976 &index,
8977 &attributes,
8978 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008980 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008982 ASSERT(holder->IsContext());
8983 // If the "property" we were looking for is a local variable, the
8984 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008985 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008986 // Use the hole as the receiver to signal that the receiver is implicit
8987 // and that the global receiver should be used (as distinguished from an
8988 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008989 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008990 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008991 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008992 switch (binding_flags) {
8993 case MUTABLE_CHECK_INITIALIZED:
8994 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8995 if (value->IsTheHole()) {
8996 Handle<Object> reference_error =
8997 isolate->factory()->NewReferenceError("not_defined",
8998 HandleVector(&name, 1));
8999 return MakePair(isolate->Throw(*reference_error), NULL);
9000 }
9001 // FALLTHROUGH
9002 case MUTABLE_IS_INITIALIZED:
9003 case IMMUTABLE_IS_INITIALIZED:
9004 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9005 ASSERT(!value->IsTheHole());
9006 return MakePair(value, *receiver);
9007 case IMMUTABLE_CHECK_INITIALIZED:
9008 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9009 case MISSING_BINDING:
9010 UNREACHABLE();
9011 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009012 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013 }
9014
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009015 // Otherwise, if the slot was found the holder is a context extension
9016 // object, subject of a with, or a global object. We read the named
9017 // property from it.
9018 if (!holder.is_null()) {
9019 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9020 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009021 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009022 Handle<Object> receiver_handle(object->IsGlobalObject()
9023 ? GlobalObject::cast(*object)->global_receiver()
9024 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009025
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009026 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009027 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009028 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009029 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030 }
9031
9032 if (throw_error) {
9033 // The property doesn't exist - throw exception.
9034 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009035 isolate->factory()->NewReferenceError("not_defined",
9036 HandleVector(&name, 1));
9037 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009038 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009039 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009040 return MakePair(isolate->heap()->undefined_value(),
9041 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009042 }
9043}
9044
9045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009046RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009047 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009048}
9049
9050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009051RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009052 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053}
9054
9055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009056RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009057 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009058 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009060 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009062 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009063 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9064 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9065 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066
9067 int index;
9068 PropertyAttributes attributes;
9069 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009070 BindingFlags binding_flags;
9071 Handle<Object> holder = context->Lookup(name,
9072 flags,
9073 &index,
9074 &attributes,
9075 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076
9077 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009078 // The property was found in a context slot.
9079 Handle<Context> context = Handle<Context>::cast(holder);
9080 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9081 context->get(index)->IsTheHole()) {
9082 Handle<Object> error =
9083 isolate->factory()->NewReferenceError("not_defined",
9084 HandleVector(&name, 1));
9085 return isolate->Throw(*error);
9086 }
9087 // Ignore if read_only variable.
9088 if ((attributes & READ_ONLY) == 0) {
9089 // Context is a fixed array and set cannot fail.
9090 context->set(index, *value);
9091 } else if (strict_mode == kStrictMode) {
9092 // Setting read only property in strict mode.
9093 Handle<Object> error =
9094 isolate->factory()->NewTypeError("strict_cannot_assign",
9095 HandleVector(&name, 1));
9096 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009097 }
9098 return *value;
9099 }
9100
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009101 // Slow case: The property is not in a context slot. It is either in a
9102 // context extension object, a property of the subject of a with, or a
9103 // property of the global object.
9104 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009106 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009107 // The property exists on the holder.
9108 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009110 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009111 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009112
9113 if (strict_mode == kStrictMode) {
9114 // Throw in strict mode (assignment to undefined variable).
9115 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009116 isolate->factory()->NewReferenceError(
9117 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009118 return isolate->Throw(*error);
9119 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009120 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009122 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123 }
9124
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009125 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009126 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009127 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009128 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009129 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009130 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009131 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009132 // Setting read only property in strict mode.
9133 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009134 isolate->factory()->NewTypeError(
9135 "strict_cannot_assign", HandleVector(&name, 1));
9136 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 }
9138 return *value;
9139}
9140
9141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009142RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009143 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009144 ASSERT(args.length() == 1);
9145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009146 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147}
9148
9149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009150RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152 ASSERT(args.length() == 1);
9153
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009154 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155}
9156
9157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009158RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009159 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009160 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009161}
9162
9163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009164RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166 ASSERT(args.length() == 1);
9167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009168 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009169 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 isolate->factory()->NewReferenceError("not_defined",
9171 HandleVector(&name, 1));
9172 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009173}
9174
9175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009176RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009177 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009178
9179 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009180 if (isolate->stack_guard()->IsStackOverflow()) {
9181 NoHandleAllocation na;
9182 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009183 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009184
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009185 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009186}
9187
9188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189static int StackSize() {
9190 int n = 0;
9191 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9192 return n;
9193}
9194
9195
9196static void PrintTransition(Object* result) {
9197 // indentation
9198 { const int nmax = 80;
9199 int n = StackSize();
9200 if (n <= nmax)
9201 PrintF("%4d:%*s", n, n, "");
9202 else
9203 PrintF("%4d:%*s", n, nmax, "...");
9204 }
9205
9206 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009207 JavaScriptFrame::PrintTop(stdout, true, false);
9208 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009209 } else {
9210 // function result
9211 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009212 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213 PrintF("\n");
9214 }
9215}
9216
9217
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009218RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9219 ASSERT(args.length() == 5);
9220 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9221 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9222 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9223 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9224 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9225 NoHandleAllocation ha;
9226 PrintF("*");
9227 obj->PrintElementsTransition(stdout,
9228 static_cast<ElementsKind>(from_kind), *from_elements,
9229 static_cast<ElementsKind>(to_kind), *to_elements);
9230 return isolate->heap()->undefined_value();
9231}
9232
9233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009234RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009235 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236 NoHandleAllocation ha;
9237 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009238 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239}
9240
9241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009242RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009243 NoHandleAllocation ha;
9244 PrintTransition(args[0]);
9245 return args[0]; // return TOS
9246}
9247
9248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009249RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250 NoHandleAllocation ha;
9251 ASSERT(args.length() == 1);
9252
9253#ifdef DEBUG
9254 if (args[0]->IsString()) {
9255 // If we have a string, assume it's a code "marker"
9256 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009257 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009258 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009259 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9260 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009261 } else {
9262 PrintF("DebugPrint: ");
9263 }
9264 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009265 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009266 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009267 HeapObject::cast(args[0])->map()->Print();
9268 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009269#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009270 // ShortPrint is available in release mode. Print is not.
9271 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272#endif
9273 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009274 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275
9276 return args[0]; // return TOS
9277}
9278
9279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009280RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009281 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009282 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009283 isolate->PrintStack();
9284 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285}
9286
9287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009288RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009290 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291
9292 // According to ECMA-262, section 15.9.1, page 117, the precision of
9293 // the number in a Date object representing a particular instant in
9294 // time is milliseconds. Therefore, we floor the result of getting
9295 // the OS time.
9296 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298}
9299
9300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009301RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009302 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009303 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009305 CONVERT_ARG_CHECKED(String, str, 0);
9306 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009307
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009308 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009309
9310 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009311 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009312 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009313 RUNTIME_ASSERT(output->HasFastElements());
9314
9315 AssertNoAllocation no_allocation;
9316
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009317 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009318 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9319 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009320 String::FlatContent str_content = str->GetFlatContent();
9321 if (str_content.IsAscii()) {
9322 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009323 output_array,
9324 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009326 ASSERT(str_content.IsTwoByte());
9327 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009328 output_array,
9329 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009330 }
9331
9332 if (result) {
9333 return *output;
9334 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009335 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009336 }
9337}
9338
9339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009340RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341 NoHandleAllocation ha;
9342 ASSERT(args.length() == 1);
9343
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009344 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009345 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009346 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009347}
9348
9349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009350RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009351 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009352 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355}
9356
9357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009358RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009359 NoHandleAllocation ha;
9360 ASSERT(args.length() == 1);
9361
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009362 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364}
9365
9366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009367RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009368 ASSERT(args.length() == 1);
9369 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009371 return JSGlobalObject::cast(global)->global_receiver();
9372}
9373
9374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009375RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009376 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009377 ASSERT_EQ(1, args.length());
9378 CONVERT_ARG_CHECKED(String, source, 0);
9379
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009380 source = Handle<String>(source->TryFlattenGetString());
9381 // Optimized fast case where we only have ascii characters.
9382 Handle<Object> result;
9383 if (source->IsSeqAsciiString()) {
9384 result = JsonParser<true>::Parse(source);
9385 } else {
9386 result = JsonParser<false>::Parse(source);
9387 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009388 if (result.is_null()) {
9389 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009390 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009391 return Failure::Exception();
9392 }
9393 return *result;
9394}
9395
9396
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009397bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9398 Handle<Context> context) {
9399 if (context->allow_code_gen_from_strings()->IsFalse()) {
9400 // Check with callback if set.
9401 AllowCodeGenerationFromStringsCallback callback =
9402 isolate->allow_code_gen_callback();
9403 if (callback == NULL) {
9404 // No callback set and code generation disallowed.
9405 return false;
9406 } else {
9407 // Callback set. Let it decide if code generation is allowed.
9408 VMState state(isolate, EXTERNAL);
9409 return callback(v8::Utils::ToLocal(context));
9410 }
9411 }
9412 return true;
9413}
9414
9415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009416RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009417 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009418 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009419 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009420
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009421 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009422 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009423
9424 // Check if global context allows code generation from
9425 // strings. Throw an exception if it doesn't.
9426 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9427 return isolate->Throw(*isolate->factory()->NewError(
9428 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9429 }
9430
9431 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009432 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009433 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009434 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009435 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9437 context,
9438 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009439 return *fun;
9440}
9441
9442
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009443static ObjectPair CompileGlobalEval(Isolate* isolate,
9444 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009445 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009446 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009447 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009448 Handle<Context> context = Handle<Context>(isolate->context());
9449 Handle<Context> global_context = Handle<Context>(context->global_context());
9450
9451 // Check if global context allows code generation from
9452 // strings. Throw an exception if it doesn't.
9453 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9454 isolate->Throw(*isolate->factory()->NewError(
9455 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9456 return MakePair(Failure::Exception(), NULL);
9457 }
9458
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009459 // Deal with a normal eval call with a string argument. Compile it
9460 // and return the compiled function bound in the local context.
9461 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9462 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009463 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009464 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009465 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009466 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009467 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009468 Handle<JSFunction> compiled =
9469 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009470 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009471 return MakePair(*compiled, *receiver);
9472}
9473
9474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009475RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009476 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009478 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009479 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009480
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009481 // If "eval" didn't refer to the original GlobalEval, it's not a
9482 // direct call to eval.
9483 // (And even if it is, but the first argument isn't a string, just let
9484 // execution default to an indirect call to eval, which will also return
9485 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009487 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009488 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009489 }
9490
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009491 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009492 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009493 return CompileGlobalEval(isolate,
9494 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009495 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009496 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009497 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009498}
9499
9500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009501RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009502 // This utility adjusts the property attributes for newly created Function
9503 // object ("new Function(...)") by changing the map.
9504 // All it does is changing the prototype property to enumerable
9505 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009506 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009507 ASSERT(args.length() == 1);
9508 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009509
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009510 Handle<Map> map = func->shared()->is_classic_mode()
9511 ? isolate->function_instance_map()
9512 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513
9514 ASSERT(func->map()->instance_type() == map->instance_type());
9515 ASSERT(func->map()->instance_size() == map->instance_size());
9516 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009517 return *func;
9518}
9519
9520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009521RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009522 // Allocate a block of memory in NewSpace (filled with a filler).
9523 // Use as fallback for allocation in generated code when NewSpace
9524 // is full.
9525 ASSERT(args.length() == 1);
9526 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9527 int size = size_smi->value();
9528 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9529 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009530 Heap* heap = isolate->heap();
9531 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009532 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009533 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009534 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009535 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009536 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009537 }
9538 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009539 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009540}
9541
9542
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009543// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009544// array. Returns true if the element was pushed on the stack and
9545// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009546RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009547 ASSERT(args.length() == 2);
9548 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009549 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009550 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009551 int length = Smi::cast(array->length())->value();
9552 FixedArray* elements = FixedArray::cast(array->elements());
9553 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009555 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009556 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009557 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009558 { MaybeObject* maybe_obj =
9559 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009560 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9561 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009562 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009563}
9564
9565
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009566/**
9567 * A simple visitor visits every element of Array's.
9568 * The backend storage can be a fixed array for fast elements case,
9569 * or a dictionary for sparse array. Since Dictionary is a subtype
9570 * of FixedArray, the class can be used by both fast and slow cases.
9571 * The second parameter of the constructor, fast_elements, specifies
9572 * whether the storage is a FixedArray or Dictionary.
9573 *
9574 * An index limit is used to deal with the situation that a result array
9575 * length overflows 32-bit non-negative integer.
9576 */
9577class ArrayConcatVisitor {
9578 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009579 ArrayConcatVisitor(Isolate* isolate,
9580 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009581 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009582 isolate_(isolate),
9583 storage_(Handle<FixedArray>::cast(
9584 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009585 index_offset_(0u),
9586 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009587
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009588 ~ArrayConcatVisitor() {
9589 clear_storage();
9590 }
9591
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009592 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009593 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009594 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009595
9596 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009597 if (index < static_cast<uint32_t>(storage_->length())) {
9598 storage_->set(index, *elm);
9599 return;
9600 }
9601 // Our initial estimate of length was foiled, possibly by
9602 // getters on the arrays increasing the length of later arrays
9603 // during iteration.
9604 // This shouldn't happen in anything but pathological cases.
9605 SetDictionaryMode(index);
9606 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009607 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009608 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009609 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009610 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009611 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009612 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009613 // Dictionary needed to grow.
9614 clear_storage();
9615 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009616 }
9617}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009618
9619 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009620 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9621 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009622 } else {
9623 index_offset_ += delta;
9624 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009625 }
9626
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009627 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009629 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009630 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009631 Handle<Map> map;
9632 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009633 map = isolate_->factory()->GetElementsTransitionMap(array,
9634 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009635 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009636 map = isolate_->factory()->GetElementsTransitionMap(array,
9637 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009638 }
9639 array->set_map(*map);
9640 array->set_length(*length);
9641 array->set_elements(*storage_);
9642 return array;
9643 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009644
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009645 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009646 // Convert storage to dictionary mode.
9647 void SetDictionaryMode(uint32_t index) {
9648 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009649 Handle<FixedArray> current_storage(*storage_);
9650 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009651 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009652 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9653 for (uint32_t i = 0; i < current_length; i++) {
9654 HandleScope loop_scope;
9655 Handle<Object> element(current_storage->get(i));
9656 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009657 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009659 if (!new_storage.is_identical_to(slow_storage)) {
9660 slow_storage = loop_scope.CloseAndEscape(new_storage);
9661 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009662 }
9663 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009664 clear_storage();
9665 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009666 fast_elements_ = false;
9667 }
9668
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009669 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009670 isolate_->global_handles()->Destroy(
9671 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009672 }
9673
9674 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009675 storage_ = Handle<FixedArray>::cast(
9676 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009677 }
9678
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009679 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009680 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009681 // Index after last seen index. Always less than or equal to
9682 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009683 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009684 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009685};
9686
9687
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009688static uint32_t EstimateElementCount(Handle<JSArray> array) {
9689 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9690 int element_count = 0;
9691 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009692 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009693 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009694 // Fast elements can't have lengths that are not representable by
9695 // a 32-bit signed integer.
9696 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9697 int fast_length = static_cast<int>(length);
9698 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9699 for (int i = 0; i < fast_length; i++) {
9700 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009701 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009702 break;
9703 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009704 case FAST_DOUBLE_ELEMENTS:
9705 // TODO(1810): Decide if it's worthwhile to implement this.
9706 UNREACHABLE();
9707 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009708 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009709 Handle<NumberDictionary> dictionary(
9710 NumberDictionary::cast(array->elements()));
9711 int capacity = dictionary->Capacity();
9712 for (int i = 0; i < capacity; i++) {
9713 Handle<Object> key(dictionary->KeyAt(i));
9714 if (dictionary->IsKey(*key)) {
9715 element_count++;
9716 }
9717 }
9718 break;
9719 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009720 case NON_STRICT_ARGUMENTS_ELEMENTS:
9721 case EXTERNAL_BYTE_ELEMENTS:
9722 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9723 case EXTERNAL_SHORT_ELEMENTS:
9724 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9725 case EXTERNAL_INT_ELEMENTS:
9726 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9727 case EXTERNAL_FLOAT_ELEMENTS:
9728 case EXTERNAL_DOUBLE_ELEMENTS:
9729 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009730 // External arrays are always dense.
9731 return length;
9732 }
9733 // As an estimate, we assume that the prototype doesn't contain any
9734 // inherited elements.
9735 return element_count;
9736}
9737
9738
9739
9740template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009741static void IterateExternalArrayElements(Isolate* isolate,
9742 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009743 bool elements_are_ints,
9744 bool elements_are_guaranteed_smis,
9745 ArrayConcatVisitor* visitor) {
9746 Handle<ExternalArrayClass> array(
9747 ExternalArrayClass::cast(receiver->elements()));
9748 uint32_t len = static_cast<uint32_t>(array->length());
9749
9750 ASSERT(visitor != NULL);
9751 if (elements_are_ints) {
9752 if (elements_are_guaranteed_smis) {
9753 for (uint32_t j = 0; j < len; j++) {
9754 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009755 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009756 visitor->visit(j, e);
9757 }
9758 } else {
9759 for (uint32_t j = 0; j < len; j++) {
9760 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009761 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009762 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9763 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9764 visitor->visit(j, e);
9765 } else {
9766 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009767 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009768 visitor->visit(j, e);
9769 }
9770 }
9771 }
9772 } else {
9773 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009774 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009775 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009776 visitor->visit(j, e);
9777 }
9778 }
9779}
9780
9781
9782// Used for sorting indices in a List<uint32_t>.
9783static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9784 uint32_t a = *ap;
9785 uint32_t b = *bp;
9786 return (a == b) ? 0 : (a < b) ? -1 : 1;
9787}
9788
9789
9790static void CollectElementIndices(Handle<JSObject> object,
9791 uint32_t range,
9792 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009793 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009794 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009795 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009796 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009797 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9798 uint32_t length = static_cast<uint32_t>(elements->length());
9799 if (range < length) length = range;
9800 for (uint32_t i = 0; i < length; i++) {
9801 if (!elements->get(i)->IsTheHole()) {
9802 indices->Add(i);
9803 }
9804 }
9805 break;
9806 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009807 case FAST_DOUBLE_ELEMENTS: {
9808 // TODO(1810): Decide if it's worthwhile to implement this.
9809 UNREACHABLE();
9810 break;
9811 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009812 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009813 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009814 uint32_t capacity = dict->Capacity();
9815 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009816 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009817 Handle<Object> k(dict->KeyAt(j));
9818 if (dict->IsKey(*k)) {
9819 ASSERT(k->IsNumber());
9820 uint32_t index = static_cast<uint32_t>(k->Number());
9821 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009822 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009823 }
9824 }
9825 }
9826 break;
9827 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009828 default: {
9829 int dense_elements_length;
9830 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009831 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009832 dense_elements_length =
9833 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009834 break;
9835 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009836 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009837 dense_elements_length =
9838 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 break;
9840 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009841 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009842 dense_elements_length =
9843 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009844 break;
9845 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009846 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009847 dense_elements_length =
9848 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 break;
9850 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009851 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009852 dense_elements_length =
9853 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 break;
9855 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009856 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009857 dense_elements_length =
9858 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009859 break;
9860 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009861 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009862 dense_elements_length =
9863 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009864 break;
9865 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009866 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009867 dense_elements_length =
9868 ExternalFloatArray::cast(object->elements())->length();
9869 break;
9870 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009871 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009872 dense_elements_length =
9873 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009874 break;
9875 }
9876 default:
9877 UNREACHABLE();
9878 dense_elements_length = 0;
9879 break;
9880 }
9881 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9882 if (range <= length) {
9883 length = range;
9884 // We will add all indices, so we might as well clear it first
9885 // and avoid duplicates.
9886 indices->Clear();
9887 }
9888 for (uint32_t i = 0; i < length; i++) {
9889 indices->Add(i);
9890 }
9891 if (length == range) return; // All indices accounted for already.
9892 break;
9893 }
9894 }
9895
9896 Handle<Object> prototype(object->GetPrototype());
9897 if (prototype->IsJSObject()) {
9898 // The prototype will usually have no inherited element indices,
9899 // but we have to check.
9900 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9901 }
9902}
9903
9904
9905/**
9906 * A helper function that visits elements of a JSArray in numerical
9907 * order.
9908 *
9909 * The visitor argument called for each existing element in the array
9910 * with the element index and the element's value.
9911 * Afterwards it increments the base-index of the visitor by the array
9912 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009913 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009914 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009915static bool IterateElements(Isolate* isolate,
9916 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009917 ArrayConcatVisitor* visitor) {
9918 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9919 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009920 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009921 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 // Run through the elements FixedArray and use HasElement and GetElement
9923 // to check the prototype for missing elements.
9924 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9925 int fast_length = static_cast<int>(length);
9926 ASSERT(fast_length <= elements->length());
9927 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928 HandleScope loop_scope(isolate);
9929 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009930 if (!element_value->IsTheHole()) {
9931 visitor->visit(j, element_value);
9932 } else if (receiver->HasElement(j)) {
9933 // Call GetElement on receiver, not its prototype, or getters won't
9934 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009935 element_value = Object::GetElement(receiver, j);
9936 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009937 visitor->visit(j, element_value);
9938 }
9939 }
9940 break;
9941 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009942 case FAST_DOUBLE_ELEMENTS: {
9943 // TODO(1810): Decide if it's worthwhile to implement this.
9944 UNREACHABLE();
9945 break;
9946 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009947 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009948 Handle<NumberDictionary> dict(receiver->element_dictionary());
9949 List<uint32_t> indices(dict->Capacity() / 2);
9950 // Collect all indices in the object and the prototypes less
9951 // than length. This might introduce duplicates in the indices list.
9952 CollectElementIndices(receiver, length, &indices);
9953 indices.Sort(&compareUInt32);
9954 int j = 0;
9955 int n = indices.length();
9956 while (j < n) {
9957 HandleScope loop_scope;
9958 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009959 Handle<Object> element = Object::GetElement(receiver, index);
9960 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009961 visitor->visit(index, element);
9962 // Skip to next different index (i.e., omit duplicates).
9963 do {
9964 j++;
9965 } while (j < n && indices[j] == index);
9966 }
9967 break;
9968 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009969 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009970 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9971 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009972 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009973 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009974 visitor->visit(j, e);
9975 }
9976 break;
9977 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009978 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009979 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009981 break;
9982 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009983 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009984 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009985 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009986 break;
9987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 break;
9992 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009993 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009994 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 break;
9997 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009998 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009999 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010000 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010001 break;
10002 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010003 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010004 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010005 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010006 break;
10007 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010008 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010009 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010011 break;
10012 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010013 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010014 IterateExternalArrayElements<ExternalDoubleArray, double>(
10015 isolate, receiver, false, false, visitor);
10016 break;
10017 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010018 default:
10019 UNREACHABLE();
10020 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010021 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010022 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010023 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010024}
10025
10026
10027/**
10028 * Array::concat implementation.
10029 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010030 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010031 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010032 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010033RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010034 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010035 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010036
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10038 int argument_count = static_cast<int>(arguments->length()->Number());
10039 RUNTIME_ASSERT(arguments->HasFastElements());
10040 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010041
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 // Pass 1: estimate the length and number of elements of the result.
10043 // The actual length can be larger if any of the arguments have getters
10044 // that mutate other arguments (but will otherwise be precise).
10045 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010046
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 uint32_t estimate_result_length = 0;
10048 uint32_t estimate_nof_elements = 0;
10049 {
10050 for (int i = 0; i < argument_count; i++) {
10051 HandleScope loop_scope;
10052 Handle<Object> obj(elements->get(i));
10053 uint32_t length_estimate;
10054 uint32_t element_estimate;
10055 if (obj->IsJSArray()) {
10056 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010057 // TODO(1810): Find out if it's worthwhile to properly support
10058 // arbitrary ElementsKinds. For now, pessimistically transition to
10059 // FAST_ELEMENTS.
10060 if (array->HasFastDoubleElements()) {
10061 array = Handle<JSArray>::cast(
10062 TransitionElementsKind(array, FAST_ELEMENTS));
10063 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010064 length_estimate =
10065 static_cast<uint32_t>(array->length()->Number());
10066 element_estimate =
10067 EstimateElementCount(array);
10068 } else {
10069 length_estimate = 1;
10070 element_estimate = 1;
10071 }
10072 // Avoid overflows by capping at kMaxElementCount.
10073 if (JSObject::kMaxElementCount - estimate_result_length <
10074 length_estimate) {
10075 estimate_result_length = JSObject::kMaxElementCount;
10076 } else {
10077 estimate_result_length += length_estimate;
10078 }
10079 if (JSObject::kMaxElementCount - estimate_nof_elements <
10080 element_estimate) {
10081 estimate_nof_elements = JSObject::kMaxElementCount;
10082 } else {
10083 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010084 }
10085 }
10086 }
10087
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010088 // If estimated number of elements is more than half of length, a
10089 // fixed array (fast case) is more time and space-efficient than a
10090 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010091 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010092
10093 Handle<FixedArray> storage;
10094 if (fast_case) {
10095 // The backing storage array must have non-existing elements to
10096 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010097 storage = isolate->factory()->NewFixedArrayWithHoles(
10098 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010099 } else {
10100 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10101 uint32_t at_least_space_for = estimate_nof_elements +
10102 (estimate_nof_elements >> 2);
10103 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010104 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010105 }
10106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010107 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010108
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010109 for (int i = 0; i < argument_count; i++) {
10110 Handle<Object> obj(elements->get(i));
10111 if (obj->IsJSArray()) {
10112 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010113 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010114 return Failure::Exception();
10115 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010116 } else {
10117 visitor.visit(0, obj);
10118 visitor.increase_index_offset(1);
10119 }
10120 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010121
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010122 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010123}
10124
10125
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010126// This will not allocate (flatten the string), but it may run
10127// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010128RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010129 NoHandleAllocation ha;
10130 ASSERT(args.length() == 1);
10131
10132 CONVERT_CHECKED(String, string, args[0]);
10133 StringInputBuffer buffer(string);
10134 while (buffer.has_more()) {
10135 uint16_t character = buffer.GetNext();
10136 PrintF("%c", character);
10137 }
10138 return string;
10139}
10140
ager@chromium.org5ec48922009-05-05 07:25:34 +000010141// Moves all own elements of an object, that are below a limit, to positions
10142// starting at zero. All undefined values are placed after non-undefined values,
10143// and are followed by non-existing element. Does not change the length
10144// property.
10145// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010146RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010147 ASSERT(args.length() == 2);
10148 CONVERT_CHECKED(JSObject, object, args[0]);
10149 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10150 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151}
10152
10153
10154// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010155RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010156 ASSERT(args.length() == 2);
10157 CONVERT_CHECKED(JSArray, from, args[0]);
10158 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010159 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010160 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010161 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010162 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10163 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010164 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010165 } else if (new_elements->map() ==
10166 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010167 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010168 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010169 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010170 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010171 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010172 Object* new_map;
10173 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010174 to->set_map(Map::cast(new_map));
10175 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010177 Object* obj;
10178 { MaybeObject* maybe_obj = from->ResetElements();
10179 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10180 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010181 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010182 return to;
10183}
10184
10185
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010186// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010187RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010189 CONVERT_CHECKED(JSObject, object, args[0]);
10190 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010191 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010192 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010193 } else if (object->IsJSArray()) {
10194 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010195 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010196 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197 }
10198}
10199
10200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010201RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010203
10204 ASSERT_EQ(3, args.length());
10205
ager@chromium.orgac091b72010-05-05 07:34:42 +000010206 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010207 Handle<Object> key1 = args.at<Object>(1);
10208 Handle<Object> key2 = args.at<Object>(2);
10209
10210 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010211 if (!key1->ToArrayIndex(&index1)
10212 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010214 }
10215
ager@chromium.orgac091b72010-05-05 07:34:42 +000010216 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010217 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010219 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010220 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010222 RETURN_IF_EMPTY_HANDLE(isolate,
10223 SetElement(jsobject, index1, tmp2, kStrictMode));
10224 RETURN_IF_EMPTY_HANDLE(isolate,
10225 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010228}
10229
10230
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010231// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010232// might have elements. Can either return keys (positive integers) or
10233// intervals (pair of a negative integer (-start-1) followed by a
10234// positive (length)) or undefined values.
10235// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010236RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010238 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010239 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010241 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242 // Create an array and get all the keys into it, then remove all the
10243 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010244 bool threw = false;
10245 Handle<FixedArray> keys =
10246 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10247 if (threw) return Failure::Exception();
10248
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 int keys_length = keys->length();
10250 for (int i = 0; i < keys_length; i++) {
10251 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010252 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010253 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 // Zap invalid keys.
10255 keys->set_undefined(i);
10256 }
10257 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010258 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010260 ASSERT(array->HasFastElements() ||
10261 array->HasFastSmiOnlyElements() ||
10262 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010263 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010265 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010266 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010267 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010268 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010269 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010270 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010273 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 }
10275}
10276
10277
10278// DefineAccessor takes an optional final argument which is the
10279// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10280// to the way accessors are implemented, it is set for both the getter
10281// and setter on the first call to DefineAccessor and ignored on
10282// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010283RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10285 // Compute attributes.
10286 PropertyAttributes attributes = NONE;
10287 if (args.length() == 5) {
10288 CONVERT_CHECKED(Smi, attrs, args[4]);
10289 int value = attrs->value();
10290 // Only attribute bits should be set.
10291 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10292 attributes = static_cast<PropertyAttributes>(value);
10293 }
10294
10295 CONVERT_CHECKED(JSObject, obj, args[0]);
10296 CONVERT_CHECKED(String, name, args[1]);
10297 CONVERT_CHECKED(Smi, flag, args[2]);
10298 CONVERT_CHECKED(JSFunction, fun, args[3]);
10299 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10300}
10301
10302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010303RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304 ASSERT(args.length() == 3);
10305 CONVERT_CHECKED(JSObject, obj, args[0]);
10306 CONVERT_CHECKED(String, name, args[1]);
10307 CONVERT_CHECKED(Smi, flag, args[2]);
10308 return obj->LookupAccessor(name, flag->value() == 0);
10309}
10310
10311
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010312#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010313RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010314 ASSERT(args.length() == 0);
10315 return Execution::DebugBreakHelper();
10316}
10317
10318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010319// Helper functions for wrapping and unwrapping stack frame ids.
10320static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010321 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322 return Smi::FromInt(id >> 2);
10323}
10324
10325
10326static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10327 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10328}
10329
10330
10331// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010332// args[0]: debug event listener function to set or null or undefined for
10333// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010335RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010336 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010337 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10338 args[0]->IsUndefined() ||
10339 args[0]->IsNull());
10340 Handle<Object> callback = args.at<Object>(0);
10341 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010344 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010345}
10346
10347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010348RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010349 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350 isolate->stack_guard()->DebugBreak();
10351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352}
10353
10354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355static MaybeObject* DebugLookupResultValue(Heap* heap,
10356 Object* receiver,
10357 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010358 LookupResult* result,
10359 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010360 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010361 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010362 case NORMAL:
10363 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010364 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010365 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366 }
10367 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010368 case FIELD:
10369 value =
10370 JSObject::cast(
10371 result->holder())->FastPropertyAt(result->GetFieldIndex());
10372 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010373 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010374 }
10375 return value;
10376 case CONSTANT_FUNCTION:
10377 return result->GetConstantFunction();
10378 case CALLBACKS: {
10379 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010380 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010381 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10382 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010383 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010384 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010385 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010386 maybe_value = heap->isolate()->pending_exception();
10387 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010388 if (caught_exception != NULL) {
10389 *caught_exception = true;
10390 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010391 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010392 }
10393 return value;
10394 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010395 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010396 }
10397 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010399 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010400 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010401 case CONSTANT_TRANSITION:
10402 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010404 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010406 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010408 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410}
10411
10412
ager@chromium.org32912102009-01-16 10:38:43 +000010413// Get debugger related details for an object property.
10414// args[0]: object holding property
10415// args[1]: name of the property
10416//
10417// The array returned contains the following information:
10418// 0: Property value
10419// 1: Property details
10420// 2: Property value is exception
10421// 3: Getter function if defined
10422// 4: Setter function if defined
10423// Items 2-4 are only filled if the property has either a getter or a setter
10424// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010425RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010426 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427
10428 ASSERT(args.length() == 2);
10429
10430 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10431 CONVERT_ARG_CHECKED(String, name, 1);
10432
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010433 // Make sure to set the current context to the context before the debugger was
10434 // entered (if the debugger is entered). The reason for switching context here
10435 // is that for some property lookups (accessors and interceptors) callbacks
10436 // into the embedding application can occour, and the embedding application
10437 // could have the assumption that its own global context is the current
10438 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010439 SaveContext save(isolate);
10440 if (isolate->debug()->InDebugger()) {
10441 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010442 }
10443
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010444 // Skip the global proxy as it has no properties and always delegates to the
10445 // real global object.
10446 if (obj->IsJSGlobalProxy()) {
10447 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10448 }
10449
10450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451 // Check if the name is trivially convertible to an index and get the element
10452 // if so.
10453 uint32_t index;
10454 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010455 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010456 Object* element_or_char;
10457 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010458 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010459 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10460 return maybe_element_or_char;
10461 }
10462 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010463 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010465 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010466 }
10467
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010468 // Find the number of objects making up this.
10469 int length = LocalPrototypeChainLength(*obj);
10470
10471 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010472 Handle<JSObject> jsproto = obj;
10473 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010474 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010475 jsproto->LocalLookup(*name, &result);
10476 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010477 // LookupResult is not GC safe as it holds raw object pointers.
10478 // GC can happen later in this code so put the required fields into
10479 // local variables using handles when required for later use.
10480 PropertyType result_type = result.type();
10481 Handle<Object> result_callback_obj;
10482 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010483 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10484 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010485 }
10486 Smi* property_details = result.GetPropertyDetails().AsSmi();
10487 // DebugLookupResultValue can cause GC so details from LookupResult needs
10488 // to be copied to handles before this.
10489 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010490 Object* raw_value;
10491 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010492 DebugLookupResultValue(isolate->heap(), *obj, *name,
10493 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010494 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10495 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010496 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010497
10498 // If the callback object is a fixed array then it contains JavaScript
10499 // getter and/or setter.
10500 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10501 result_callback_obj->IsFixedArray();
10502 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010504 details->set(0, *value);
10505 details->set(1, property_details);
10506 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010507 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010508 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10509 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10510 }
10511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010512 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010513 }
10514 if (i < length - 1) {
10515 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10516 }
10517 }
10518
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010519 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520}
10521
10522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010523RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525
10526 ASSERT(args.length() == 2);
10527
10528 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10529 CONVERT_ARG_CHECKED(String, name, 1);
10530
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010531 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532 obj->Lookup(*name, &result);
10533 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010534 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010535 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010536 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010537}
10538
10539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540// Return the property type calculated from the property details.
10541// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010542RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010543 ASSERT(args.length() == 1);
10544 CONVERT_CHECKED(Smi, details, args[0]);
10545 PropertyType type = PropertyDetails(details).type();
10546 return Smi::FromInt(static_cast<int>(type));
10547}
10548
10549
10550// Return the property attribute calculated from the property details.
10551// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010552RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553 ASSERT(args.length() == 1);
10554 CONVERT_CHECKED(Smi, details, args[0]);
10555 PropertyAttributes attributes = PropertyDetails(details).attributes();
10556 return Smi::FromInt(static_cast<int>(attributes));
10557}
10558
10559
10560// Return the property insertion index calculated from the property details.
10561// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010562RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563 ASSERT(args.length() == 1);
10564 CONVERT_CHECKED(Smi, details, args[0]);
10565 int index = PropertyDetails(details).index();
10566 return Smi::FromInt(index);
10567}
10568
10569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010570// Return property value from named interceptor.
10571// args[0]: object
10572// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010573RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010574 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575 ASSERT(args.length() == 2);
10576 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10577 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10578 CONVERT_ARG_CHECKED(String, name, 1);
10579
10580 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010581 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582}
10583
10584
10585// Return element value from indexed interceptor.
10586// args[0]: object
10587// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010588RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010589 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010590 ASSERT(args.length() == 2);
10591 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10592 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10593 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10594
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010595 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596}
10597
10598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010599RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600 ASSERT(args.length() >= 1);
10601 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010602 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010603 if (isolate->debug()->break_id() == 0 ||
10604 break_id != isolate->debug()->break_id()) {
10605 return isolate->Throw(
10606 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607 }
10608
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010609 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610}
10611
10612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010613RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010614 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 ASSERT(args.length() == 1);
10616
10617 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010618 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010619 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10620 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010621 if (!maybe_result->ToObject(&result)) return maybe_result;
10622 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623
10624 // Count all frames which are relevant to debugging stack trace.
10625 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010626 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010627 if (id == StackFrame::NO_ID) {
10628 // If there is no JavaScript stack frame count is 0.
10629 return Smi::FromInt(0);
10630 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010631
10632 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10633 n += it.frame()->GetInlineCount();
10634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635 return Smi::FromInt(n);
10636}
10637
10638
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010639class FrameInspector {
10640 public:
10641 FrameInspector(JavaScriptFrame* frame,
10642 int inlined_frame_index,
10643 Isolate* isolate)
10644 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10645 // Calculate the deoptimized frame.
10646 if (frame->is_optimized()) {
10647 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10648 frame, inlined_frame_index, isolate);
10649 }
10650 has_adapted_arguments_ = frame_->has_adapted_arguments();
10651 is_optimized_ = frame_->is_optimized();
10652 }
10653
10654 ~FrameInspector() {
10655 // Get rid of the calculated deoptimized frame if any.
10656 if (deoptimized_frame_ != NULL) {
10657 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10658 isolate_);
10659 }
10660 }
10661
10662 int GetParametersCount() {
10663 return is_optimized_
10664 ? deoptimized_frame_->parameters_count()
10665 : frame_->ComputeParametersCount();
10666 }
10667 int expression_count() { return deoptimized_frame_->expression_count(); }
10668 Object* GetFunction() {
10669 return is_optimized_
10670 ? deoptimized_frame_->GetFunction()
10671 : frame_->function();
10672 }
10673 Object* GetParameter(int index) {
10674 return is_optimized_
10675 ? deoptimized_frame_->GetParameter(index)
10676 : frame_->GetParameter(index);
10677 }
10678 Object* GetExpression(int index) {
10679 return is_optimized_
10680 ? deoptimized_frame_->GetExpression(index)
10681 : frame_->GetExpression(index);
10682 }
10683
10684 // To inspect all the provided arguments the frame might need to be
10685 // replaced with the arguments frame.
10686 void SetArgumentsFrame(JavaScriptFrame* frame) {
10687 ASSERT(has_adapted_arguments_);
10688 frame_ = frame;
10689 is_optimized_ = frame_->is_optimized();
10690 ASSERT(!is_optimized_);
10691 }
10692
10693 private:
10694 JavaScriptFrame* frame_;
10695 DeoptimizedFrameInfo* deoptimized_frame_;
10696 Isolate* isolate_;
10697 bool is_optimized_;
10698 bool has_adapted_arguments_;
10699
10700 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10701};
10702
10703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704static const int kFrameDetailsFrameIdIndex = 0;
10705static const int kFrameDetailsReceiverIndex = 1;
10706static const int kFrameDetailsFunctionIndex = 2;
10707static const int kFrameDetailsArgumentCountIndex = 3;
10708static const int kFrameDetailsLocalCountIndex = 4;
10709static const int kFrameDetailsSourcePositionIndex = 5;
10710static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010711static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010712static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010713static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010714
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010715
10716static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10717 JavaScriptFrame* frame) {
10718 SaveContext* save = isolate->save_context();
10719 while (save != NULL && !save->IsBelowFrame(frame)) {
10720 save = save->prev();
10721 }
10722 ASSERT(save != NULL);
10723 return save;
10724}
10725
10726
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010727// Return an array with frame details
10728// args[0]: number: break id
10729// args[1]: number: frame index
10730//
10731// The array returned contains the following information:
10732// 0: Frame id
10733// 1: Receiver
10734// 2: Function
10735// 3: Argument count
10736// 4: Local count
10737// 5: Source position
10738// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010739// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010740// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010741// Arguments name, value
10742// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010743// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010744RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010745 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746 ASSERT(args.length() == 2);
10747
10748 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010749 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010750 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10751 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010752 if (!maybe_check->ToObject(&check)) return maybe_check;
10753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010754 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010755 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010756
10757 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010758 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010759 if (id == StackFrame::NO_ID) {
10760 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010761 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010762 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010763
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010764 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010765
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010766 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010767 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010769 if (index < count + it.frame()->GetInlineCount()) break;
10770 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010772 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010774 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010775 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010776 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010777 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010778 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780 // Traverse the saved contexts chain to find the active context for the
10781 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010782 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783
10784 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010785 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786
10787 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010788 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010789 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010791 // Check for constructor frame. Inlined frames cannot be construct calls.
10792 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010793 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010794 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010796 // Get scope info and read from it for local variable information.
10797 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010798 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010799 Handle<ScopeInfo> scope_info(shared->scope_info());
10800 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010801
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010802 // Get the locals names and values into a temporary array.
10803 //
10804 // TODO(1240907): Hide compiler-introduced stack variables
10805 // (e.g. .result)? For users of the debugger, they will probably be
10806 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010807 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010808 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010809
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010810 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010811 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010812 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010813 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010814 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010815 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010816 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010817 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010818 // Get the context containing declarations.
10819 Handle<Context> context(
10820 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010821 for (; i < scope_info->LocalCount(); ++i) {
10822 Handle<String> name(scope_info->LocalName(i));
10823 VariableMode mode;
10824 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010825 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010826 locals->set(i * 2 + 1, context->get(
10827 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010828 }
10829 }
10830
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010831 // Check whether this frame is positioned at return. If not top
10832 // frame or if the frame is optimized it cannot be at a return.
10833 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010834 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010835 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010836 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010837
10838 // If positioned just before return find the value to be returned and add it
10839 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010840 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010841 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010842 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010843 Address internal_frame_sp = NULL;
10844 while (!it2.done()) {
10845 if (it2.frame()->is_internal()) {
10846 internal_frame_sp = it2.frame()->sp();
10847 } else {
10848 if (it2.frame()->is_java_script()) {
10849 if (it2.frame()->id() == it.frame()->id()) {
10850 // The internal frame just before the JavaScript frame contains the
10851 // value to return on top. A debug break at return will create an
10852 // internal frame to store the return value (eax/rax/r0) before
10853 // entering the debug break exit frame.
10854 if (internal_frame_sp != NULL) {
10855 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010856 Handle<Object>(Memory::Object_at(internal_frame_sp),
10857 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010858 break;
10859 }
10860 }
10861 }
10862
10863 // Indicate that the previous frame was not an internal frame.
10864 internal_frame_sp = NULL;
10865 }
10866 it2.Advance();
10867 }
10868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869
10870 // Now advance to the arguments adapter frame (if any). It contains all
10871 // the provided parameters whereas the function frame always have the number
10872 // of arguments matching the functions parameters. The rest of the
10873 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010874 if (it.frame()->has_adapted_arguments()) {
10875 it.AdvanceToArgumentsFrame();
10876 frame_inspector.SetArgumentsFrame(it.frame());
10877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878
10879 // Find the number of arguments to fill. At least fill the number of
10880 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010881 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010882 if (argument_count < frame_inspector.GetParametersCount()) {
10883 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010885#ifdef DEBUG
10886 if (it.frame()->is_optimized()) {
10887 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10888 }
10889#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890
10891 // Calculate the size of the result.
10892 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010893 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010894 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010895 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010896
10897 // Add the frame id.
10898 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10899
10900 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010901 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902
10903 // Add the arguments count.
10904 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10905
10906 // Add the locals count
10907 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010908 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010909
10910 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010911 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010912 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10913 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010914 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010915 }
10916
10917 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010918 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010920 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010921 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010922
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010923 // Add flags to indicate information on whether this frame is
10924 // bit 0: invoked in the debugger context.
10925 // bit 1: optimized frame.
10926 // bit 2: inlined in optimized frame
10927 int flags = 0;
10928 if (*save->context() == *isolate->debug()->debug_context()) {
10929 flags |= 1 << 0;
10930 }
10931 if (it.frame()->is_optimized()) {
10932 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010933 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010934 }
10935 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936
10937 // Fill the dynamic part.
10938 int details_index = kFrameDetailsFirstDynamicIndex;
10939
10940 // Add arguments name and value.
10941 for (int i = 0; i < argument_count; i++) {
10942 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010943 if (i < scope_info->ParameterCount()) {
10944 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010946 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947 }
10948
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010949 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010950 if (i < it.frame()->ComputeParametersCount()) {
10951 // Get the value from the stack.
10952 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010954 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955 }
10956 }
10957
10958 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010959 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 details->set(details_index++, locals->get(i));
10961 }
10962
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010963 // Add the value being returned.
10964 if (at_return) {
10965 details->set(details_index++, *return_value);
10966 }
10967
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 // Add the receiver (same as in function frame).
10969 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10970 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010971 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010972 if (!receiver->IsJSObject() &&
10973 shared->is_classic_mode() &&
10974 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010975 // If the receiver is not a JSObject and the function is not a
10976 // builtin or strict-mode we have hit an optimization where a
10977 // value object is not converted into a wrapped JS objects. To
10978 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 // by creating correct wrapper object based on the calling frame's
10980 // global context.
10981 it.Advance();
10982 Handle<Context> calling_frames_global_context(
10983 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010984 receiver =
10985 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010986 }
10987 details->set(kFrameDetailsReceiverIndex, *receiver);
10988
10989 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991}
10992
10993
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010994// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010995static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010996 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010997 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010998 Handle<Context> context,
10999 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011000 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011001 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11002 VariableMode mode;
11003 InitializationFlag init_flag;
11004 int context_index = scope_info->ContextSlotIndex(
11005 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011006
whesse@chromium.org7b260152011-06-20 15:33:18 +000011007 RETURN_IF_EMPTY_HANDLE_VALUE(
11008 isolate,
11009 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011010 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011011 Handle<Object>(context->get(context_index), isolate),
11012 NONE,
11013 kNonStrictMode),
11014 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011015 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011016
11017 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011018}
11019
11020
11021// Create a plain JSObject which materializes the local scope for the specified
11022// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011023static Handle<JSObject> MaterializeLocalScope(
11024 Isolate* isolate,
11025 JavaScriptFrame* frame,
11026 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011027 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011028 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011029 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011030 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011031
11032 // Allocate and initialize a JSObject with all the arguments, stack locals
11033 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011034 Handle<JSObject> local_scope =
11035 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011036
11037 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011038 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011039 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011040 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011041 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011042 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011043 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011044 NONE,
11045 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011046 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011047 }
11048
11049 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011050 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011051 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011052 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011053 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011054 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011055 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011056 NONE,
11057 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011058 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011059 }
11060
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011061 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011062 // Third fill all context locals.
11063 Handle<Context> frame_context(Context::cast(frame->context()));
11064 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011065 if (!CopyContextLocalsToScopeObject(
11066 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011067 return Handle<JSObject>();
11068 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011069
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011070 // Finally copy any properties from the function context extension.
11071 // These will be variables introduced by eval.
11072 if (function_context->closure() == *function) {
11073 if (function_context->has_extension() &&
11074 !function_context->IsGlobalContext()) {
11075 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011076 bool threw = false;
11077 Handle<FixedArray> keys =
11078 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11079 if (threw) return Handle<JSObject>();
11080
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011081 for (int i = 0; i < keys->length(); i++) {
11082 // Names of variables introduced by eval are strings.
11083 ASSERT(keys->get(i)->IsString());
11084 Handle<String> key(String::cast(keys->get(i)));
11085 RETURN_IF_EMPTY_HANDLE_VALUE(
11086 isolate,
11087 SetProperty(local_scope,
11088 key,
11089 GetProperty(ext, key),
11090 NONE,
11091 kNonStrictMode),
11092 Handle<JSObject>());
11093 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011094 }
11095 }
11096 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011097
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011098 return local_scope;
11099}
11100
11101
11102// Create a plain JSObject which materializes the closure content for the
11103// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011104static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11105 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011106 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011107
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011108 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011109 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011110
11111 // Allocate and initialize a JSObject with all the content of theis function
11112 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011113 Handle<JSObject> closure_scope =
11114 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011115
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011116 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011117 if (!CopyContextLocalsToScopeObject(
11118 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011119 return Handle<JSObject>();
11120 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121
11122 // Finally copy any properties from the function context extension. This will
11123 // be variables introduced by eval.
11124 if (context->has_extension()) {
11125 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011126 bool threw = false;
11127 Handle<FixedArray> keys =
11128 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11129 if (threw) return Handle<JSObject>();
11130
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011131 for (int i = 0; i < keys->length(); i++) {
11132 // Names of variables introduced by eval are strings.
11133 ASSERT(keys->get(i)->IsString());
11134 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011135 RETURN_IF_EMPTY_HANDLE_VALUE(
11136 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011137 SetProperty(closure_scope,
11138 key,
11139 GetProperty(ext, key),
11140 NONE,
11141 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011142 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011143 }
11144 }
11145
11146 return closure_scope;
11147}
11148
11149
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011150// Create a plain JSObject which materializes the scope for the specified
11151// catch context.
11152static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11153 Handle<Context> context) {
11154 ASSERT(context->IsCatchContext());
11155 Handle<String> name(String::cast(context->extension()));
11156 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11157 Handle<JSObject> catch_scope =
11158 isolate->factory()->NewJSObject(isolate->object_function());
11159 RETURN_IF_EMPTY_HANDLE_VALUE(
11160 isolate,
11161 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11162 Handle<JSObject>());
11163 return catch_scope;
11164}
11165
11166
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011167// Create a plain JSObject which materializes the block scope for the specified
11168// block context.
11169static Handle<JSObject> MaterializeBlockScope(
11170 Isolate* isolate,
11171 Handle<Context> context) {
11172 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011173 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011174
11175 // Allocate and initialize a JSObject with all the arguments, stack locals
11176 // heap locals and extension properties of the debugged function.
11177 Handle<JSObject> block_scope =
11178 isolate->factory()->NewJSObject(isolate->object_function());
11179
11180 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011181 if (!CopyContextLocalsToScopeObject(
11182 isolate, scope_info, context, block_scope)) {
11183 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011184 }
11185
11186 return block_scope;
11187}
11188
11189
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011190// Iterate over the actual scopes visible from a stack frame. The iteration
11191// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011192// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011193// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011194class ScopeIterator {
11195 public:
11196 enum ScopeType {
11197 ScopeTypeGlobal = 0,
11198 ScopeTypeLocal,
11199 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011200 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011201 ScopeTypeCatch,
11202 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011203 };
11204
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011205 ScopeIterator(Isolate* isolate,
11206 JavaScriptFrame* frame,
11207 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011208 : isolate_(isolate),
11209 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011210 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011211 function_(JSFunction::cast(frame->function())),
11212 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011213 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011214
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011215 // Catch the case when the debugger stops in an internal function.
11216 Handle<SharedFunctionInfo> shared_info(function_->shared());
11217 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11218 if (shared_info->script() == isolate->heap()->undefined_value()) {
11219 while (context_->closure() == *function_) {
11220 context_ = Handle<Context>(context_->previous(), isolate_);
11221 }
11222 return;
11223 }
11224
11225 // Get the debug info (create it if it does not exist).
11226 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11227 // Return if ensuring debug info failed.
11228 return;
11229 }
11230 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11231
11232 // Find the break point where execution has stopped.
11233 BreakLocationIterator break_location_iterator(debug_info,
11234 ALL_BREAK_LOCATIONS);
11235 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11236 if (break_location_iterator.IsExit()) {
11237 // We are within the return sequence. At the momemt it is not possible to
11238 // get a source position which is consistent with the current scope chain.
11239 // Thus all nested with, catch and block contexts are skipped and we only
11240 // provide the function scope.
11241 if (scope_info->HasContext()) {
11242 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11243 } else {
11244 while (context_->closure() == *function_) {
11245 context_ = Handle<Context>(context_->previous(), isolate_);
11246 }
11247 }
11248 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11249 } else {
11250 // Reparse the code and analyze the scopes.
11251 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11252 Handle<Script> script(Script::cast(shared_info->script()));
11253 Scope* scope = NULL;
11254
11255 // Check whether we are in global, eval or function code.
11256 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11257 if (scope_info->Type() != FUNCTION_SCOPE) {
11258 // Global or eval code.
11259 CompilationInfo info(script);
11260 if (scope_info->Type() == GLOBAL_SCOPE) {
11261 info.MarkAsGlobal();
11262 } else {
11263 ASSERT(scope_info->Type() == EVAL_SCOPE);
11264 info.MarkAsEval();
11265 info.SetCallingContext(Handle<Context>(function_->context()));
11266 }
11267 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11268 scope = info.function()->scope();
11269 }
11270 } else {
11271 // Function code
11272 CompilationInfo info(shared_info);
11273 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11274 scope = info.function()->scope();
11275 }
11276 }
11277
11278 // Retrieve the scope chain for the current position.
11279 if (scope != NULL) {
11280 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11281 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11282 } else {
11283 // A failed reparse indicates that the preparser has diverged from the
11284 // parser or that the preparse data given to the initial parse has been
11285 // faulty. We fail in debug mode but in release mode we only provide the
11286 // information we get from the context chain but nothing about
11287 // completely stack allocated scopes or stack allocated locals.
11288 UNREACHABLE();
11289 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011290 }
11291 }
11292
11293 // More scopes?
11294 bool Done() { return context_.is_null(); }
11295
11296 // Move to the next scope.
11297 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011298 ScopeType scope_type = Type();
11299 if (scope_type == ScopeTypeGlobal) {
11300 // The global scope is always the last in the chain.
11301 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011302 context_ = Handle<Context>();
11303 return;
11304 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011305 if (nested_scope_chain_.is_empty()) {
11306 context_ = Handle<Context>(context_->previous(), isolate_);
11307 } else {
11308 if (nested_scope_chain_.last()->HasContext()) {
11309 ASSERT(context_->previous() != NULL);
11310 context_ = Handle<Context>(context_->previous(), isolate_);
11311 }
11312 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011313 }
11314 }
11315
11316 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011317 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011318 if (!nested_scope_chain_.is_empty()) {
11319 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11320 switch (scope_info->Type()) {
11321 case FUNCTION_SCOPE:
11322 ASSERT(context_->IsFunctionContext() ||
11323 !scope_info->HasContext());
11324 return ScopeTypeLocal;
11325 case GLOBAL_SCOPE:
11326 ASSERT(context_->IsGlobalContext());
11327 return ScopeTypeGlobal;
11328 case WITH_SCOPE:
11329 ASSERT(context_->IsWithContext());
11330 return ScopeTypeWith;
11331 case CATCH_SCOPE:
11332 ASSERT(context_->IsCatchContext());
11333 return ScopeTypeCatch;
11334 case BLOCK_SCOPE:
11335 ASSERT(!scope_info->HasContext() ||
11336 context_->IsBlockContext());
11337 return ScopeTypeBlock;
11338 case EVAL_SCOPE:
11339 UNREACHABLE();
11340 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011341 }
11342 if (context_->IsGlobalContext()) {
11343 ASSERT(context_->global()->IsGlobalObject());
11344 return ScopeTypeGlobal;
11345 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011346 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011347 return ScopeTypeClosure;
11348 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011349 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011350 return ScopeTypeCatch;
11351 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011352 if (context_->IsBlockContext()) {
11353 return ScopeTypeBlock;
11354 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011355 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011356 return ScopeTypeWith;
11357 }
11358
11359 // Return the JavaScript object with the content of the current scope.
11360 Handle<JSObject> ScopeObject() {
11361 switch (Type()) {
11362 case ScopeIterator::ScopeTypeGlobal:
11363 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011364 case ScopeIterator::ScopeTypeLocal:
11365 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011366 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011367 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011368 case ScopeIterator::ScopeTypeWith:
11369 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011370 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11371 case ScopeIterator::ScopeTypeCatch:
11372 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011373 case ScopeIterator::ScopeTypeClosure:
11374 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011375 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011376 case ScopeIterator::ScopeTypeBlock:
11377 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011378 }
11379 UNREACHABLE();
11380 return Handle<JSObject>();
11381 }
11382
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011383 Handle<ScopeInfo> CurrentScopeInfo() {
11384 if (!nested_scope_chain_.is_empty()) {
11385 return nested_scope_chain_.last();
11386 } else if (context_->IsBlockContext()) {
11387 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11388 } else if (context_->IsFunctionContext()) {
11389 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11390 }
11391 return Handle<ScopeInfo>::null();
11392 }
11393
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011394 // Return the context for this scope. For the local context there might not
11395 // be an actual context.
11396 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011397 if (Type() == ScopeTypeGlobal ||
11398 nested_scope_chain_.is_empty()) {
11399 return context_;
11400 } else if (nested_scope_chain_.last()->HasContext()) {
11401 return context_;
11402 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011403 return Handle<Context>();
11404 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011405 }
11406
11407#ifdef DEBUG
11408 // Debug print of the content of the current scope.
11409 void DebugPrint() {
11410 switch (Type()) {
11411 case ScopeIterator::ScopeTypeGlobal:
11412 PrintF("Global:\n");
11413 CurrentContext()->Print();
11414 break;
11415
11416 case ScopeIterator::ScopeTypeLocal: {
11417 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011418 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011419 if (!CurrentContext().is_null()) {
11420 CurrentContext()->Print();
11421 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011422 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011423 if (extension->IsJSContextExtensionObject()) {
11424 extension->Print();
11425 }
11426 }
11427 }
11428 break;
11429 }
11430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011431 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011432 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011433 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011434 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011435
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011436 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011437 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011438 CurrentContext()->extension()->Print();
11439 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011440 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011441
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011442 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011443 PrintF("Closure:\n");
11444 CurrentContext()->Print();
11445 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011446 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011447 if (extension->IsJSContextExtensionObject()) {
11448 extension->Print();
11449 }
11450 }
11451 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011452
11453 default:
11454 UNREACHABLE();
11455 }
11456 PrintF("\n");
11457 }
11458#endif
11459
11460 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011461 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011462 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011463 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011464 Handle<JSFunction> function_;
11465 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011466 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011467
11468 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11469};
11470
11471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011472RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011473 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011474 ASSERT(args.length() == 2);
11475
11476 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011477 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011478 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11479 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011480 if (!maybe_check->ToObject(&check)) return maybe_check;
11481 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011482 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11483
11484 // Get the frame where the debugging is performed.
11485 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011486 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011487 JavaScriptFrame* frame = it.frame();
11488
11489 // Count the visible scopes.
11490 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011491 for (ScopeIterator it(isolate, frame, 0);
11492 !it.Done();
11493 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011494 n++;
11495 }
11496
11497 return Smi::FromInt(n);
11498}
11499
11500
11501static const int kScopeDetailsTypeIndex = 0;
11502static const int kScopeDetailsObjectIndex = 1;
11503static const int kScopeDetailsSize = 2;
11504
11505// Return an array with scope details
11506// args[0]: number: break id
11507// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011508// args[2]: number: inlined frame index
11509// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011510//
11511// The array returned contains the following information:
11512// 0: Scope type
11513// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011514RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011516 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011517
11518 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011519 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011520 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11521 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011522 if (!maybe_check->ToObject(&check)) return maybe_check;
11523 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011524 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011525 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11526 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011527
11528 // Get the frame where the debugging is performed.
11529 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011530 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011531 JavaScriptFrame* frame = frame_it.frame();
11532
11533 // Find the requested scope.
11534 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011535 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011536 for (; !it.Done() && n < index; it.Next()) {
11537 n++;
11538 }
11539 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011540 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011541 }
11542
11543 // Calculate the size of the result.
11544 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011545 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011546
11547 // Fill in scope details.
11548 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011549 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011550 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011551 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011552
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011554}
11555
11556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011557RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011558 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011559 ASSERT(args.length() == 0);
11560
11561#ifdef DEBUG
11562 // Print the scopes for the top frame.
11563 StackFrameLocator locator;
11564 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011565 for (ScopeIterator it(isolate, frame, 0);
11566 !it.Done();
11567 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011568 it.DebugPrint();
11569 }
11570#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011571 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011572}
11573
11574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011575RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011576 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011577 ASSERT(args.length() == 1);
11578
11579 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011580 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011581 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11582 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011583 if (!maybe_result->ToObject(&result)) return maybe_result;
11584 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011585
11586 // Count all archived V8 threads.
11587 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011588 for (ThreadState* thread =
11589 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011590 thread != NULL;
11591 thread = thread->Next()) {
11592 n++;
11593 }
11594
11595 // Total number of threads is current thread and archived threads.
11596 return Smi::FromInt(n + 1);
11597}
11598
11599
11600static const int kThreadDetailsCurrentThreadIndex = 0;
11601static const int kThreadDetailsThreadIdIndex = 1;
11602static const int kThreadDetailsSize = 2;
11603
11604// Return an array with thread details
11605// args[0]: number: break id
11606// args[1]: number: thread index
11607//
11608// The array returned contains the following information:
11609// 0: Is current thread?
11610// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011611RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011612 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011613 ASSERT(args.length() == 2);
11614
11615 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011616 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011617 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11618 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011619 if (!maybe_check->ToObject(&check)) return maybe_check;
11620 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011621 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11622
11623 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011624 Handle<FixedArray> details =
11625 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011626
11627 // Thread index 0 is current thread.
11628 if (index == 0) {
11629 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 details->set(kThreadDetailsCurrentThreadIndex,
11631 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011632 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011633 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011634 } else {
11635 // Find the thread with the requested index.
11636 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 ThreadState* thread =
11638 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011639 while (index != n && thread != NULL) {
11640 thread = thread->Next();
11641 n++;
11642 }
11643 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011645 }
11646
11647 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011648 details->set(kThreadDetailsCurrentThreadIndex,
11649 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011650 details->set(kThreadDetailsThreadIdIndex,
11651 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011652 }
11653
11654 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011656}
11657
11658
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011659// Sets the disable break state
11660// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011661RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011663 ASSERT(args.length() == 1);
11664 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011665 isolate->debug()->set_disable_break(disable_break);
11666 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011667}
11668
11669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011670RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 ASSERT(args.length() == 1);
11673
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011674 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11675 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011676 // Find the number of break points
11677 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011679 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011681 Handle<FixedArray>::cast(break_locations));
11682}
11683
11684
11685// Set a break point in a function
11686// args[0]: function
11687// args[1]: number: break source position (within the function source)
11688// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011689RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011690 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011691 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011692 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11693 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011694 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11695 RUNTIME_ASSERT(source_position >= 0);
11696 Handle<Object> break_point_object_arg = args.at<Object>(2);
11697
11698 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11700 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011701
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011702 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011703}
11704
11705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011706Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11707 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011708 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011709 // Iterate the heap looking for SharedFunctionInfo generated from the
11710 // script. The inner most SharedFunctionInfo containing the source position
11711 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011712 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011713 // which is found is not compiled it is compiled and the heap is iterated
11714 // again as the compilation might create inner functions from the newly
11715 // compiled function and the actual requested break point might be in one of
11716 // these functions.
11717 bool done = false;
11718 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011719 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011720 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011721 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011722 { // Extra scope for iterator and no-allocation.
11723 isolate->heap()->EnsureHeapIsIterable();
11724 AssertNoAllocation no_alloc_during_heap_iteration;
11725 HeapIterator iterator;
11726 for (HeapObject* obj = iterator.next();
11727 obj != NULL; obj = iterator.next()) {
11728 if (obj->IsSharedFunctionInfo()) {
11729 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11730 if (shared->script() == *script) {
11731 // If the SharedFunctionInfo found has the requested script data and
11732 // contains the source position it is a candidate.
11733 int start_position = shared->function_token_position();
11734 if (start_position == RelocInfo::kNoPosition) {
11735 start_position = shared->start_position();
11736 }
11737 if (start_position <= position &&
11738 position <= shared->end_position()) {
11739 // If there is no candidate or this function is within the current
11740 // candidate this is the new candidate.
11741 if (target.is_null()) {
11742 target_start_position = start_position;
11743 target = shared;
11744 } else {
11745 if (target_start_position == start_position &&
11746 shared->end_position() == target->end_position()) {
11747 // If a top-level function contain only one function
11748 // declartion the source for the top-level and the
11749 // function is the same. In that case prefer the non
11750 // top-level function.
11751 if (!shared->is_toplevel()) {
11752 target_start_position = start_position;
11753 target = shared;
11754 }
11755 } else if (target_start_position <= start_position &&
11756 shared->end_position() <= target->end_position()) {
11757 // This containment check includes equality as a function
11758 // inside a top-level function can share either start or end
11759 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011760 target_start_position = start_position;
11761 target = shared;
11762 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011763 }
11764 }
11765 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011766 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011767 } // End for loop.
11768 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011769
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011770 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 }
11773
11774 // If the candidate found is compiled we are done. NOTE: when lazy
11775 // compilation of inner functions is introduced some additional checking
11776 // needs to be done here to compile inner functions.
11777 done = target->is_compiled();
11778 if (!done) {
11779 // If the candidate is not compiled compile it to reveal any inner
11780 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011781 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011782 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011783 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784
11785 return *target;
11786}
11787
11788
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011789// Changes the state of a break point in a script and returns source position
11790// where break point was set. NOTE: Regarding performance see the NOTE for
11791// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011792// args[0]: script to set break point in
11793// args[1]: number: break source position (within the script source)
11794// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011795RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797 ASSERT(args.length() == 3);
11798 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11799 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11800 RUNTIME_ASSERT(source_position >= 0);
11801 Handle<Object> break_point_object_arg = args.at<Object>(2);
11802
11803 // Get the script from the script wrapper.
11804 RUNTIME_ASSERT(wrapper->value()->IsScript());
11805 Handle<Script> script(Script::cast(wrapper->value()));
11806
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011807 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011808 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011809 if (!result->IsUndefined()) {
11810 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11811 // Find position within function. The script position might be before the
11812 // source position of the first function.
11813 int position;
11814 if (shared->start_position() > source_position) {
11815 position = 0;
11816 } else {
11817 position = source_position - shared->start_position();
11818 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011819 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011820 position += shared->start_position();
11821 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011822 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011823 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011824}
11825
11826
11827// Clear a break point
11828// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011829RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011830 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011831 ASSERT(args.length() == 1);
11832 Handle<Object> break_point_object_arg = args.at<Object>(0);
11833
11834 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011835 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011837 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838}
11839
11840
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011841// Change the state of break on exceptions.
11842// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11843// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011844RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011845 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011847 RUNTIME_ASSERT(args[0]->IsNumber());
11848 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011850 // If the number doesn't match an enum value, the ChangeBreakOnException
11851 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852 ExceptionBreakType type =
11853 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011854 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011855 isolate->debug()->ChangeBreakOnException(type, enable);
11856 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011857}
11858
11859
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011860// Returns the state of break on exceptions
11861// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011862RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011863 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011864 ASSERT(args.length() == 1);
11865 RUNTIME_ASSERT(args[0]->IsNumber());
11866
11867 ExceptionBreakType type =
11868 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011869 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011870 return Smi::FromInt(result);
11871}
11872
11873
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011874// Prepare for stepping
11875// args[0]: break id for checking execution state
11876// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011877// args[2]: number of times to perform the step, for step out it is the number
11878// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011879RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881 ASSERT(args.length() == 3);
11882 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011883 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011884 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11885 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011886 if (!maybe_check->ToObject(&check)) return maybe_check;
11887 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890 }
11891
11892 // Get the step action and check validity.
11893 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11894 if (step_action != StepIn &&
11895 step_action != StepNext &&
11896 step_action != StepOut &&
11897 step_action != StepInMin &&
11898 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900 }
11901
11902 // Get the number of steps.
11903 int step_count = NumberToInt32(args[2]);
11904 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011905 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011906 }
11907
ager@chromium.orga1645e22009-09-09 19:27:10 +000011908 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011909 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011912 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11913 step_count);
11914 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011915}
11916
11917
11918// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011919RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011920 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011921 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011922 isolate->debug()->ClearStepping();
11923 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924}
11925
11926
11927// Creates a copy of the with context chain. The copy of the context chain is
11928// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011929static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11930 Handle<JSFunction> function,
11931 Handle<Context> base,
11932 JavaScriptFrame* frame,
11933 int inlined_frame_index) {
11934 HandleScope scope(isolate);
11935 List<Handle<ScopeInfo> > scope_chain;
11936 List<Handle<Context> > context_chain;
11937
11938 ScopeIterator it(isolate, frame, inlined_frame_index);
11939 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11940 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11941 ASSERT(!it.Done());
11942 scope_chain.Add(it.CurrentScopeInfo());
11943 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011944 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011945
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011946 // At the end of the chain. Return the base context to link to.
11947 Handle<Context> context = base;
11948
11949 // Iteratively copy and or materialize the nested contexts.
11950 while (!scope_chain.is_empty()) {
11951 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11952 Handle<Context> current = context_chain.RemoveLast();
11953 ASSERT(!(scope_info->HasContext() & current.is_null()));
11954
11955 if (scope_info->Type() == CATCH_SCOPE) {
11956 Handle<String> name(String::cast(current->extension()));
11957 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11958 context =
11959 isolate->factory()->NewCatchContext(function,
11960 context,
11961 name,
11962 thrown_object);
11963 } else if (scope_info->Type() == BLOCK_SCOPE) {
11964 // Materialize the contents of the block scope into a JSObject.
11965 Handle<JSObject> block_scope_object =
11966 MaterializeBlockScope(isolate, current);
11967 if (block_scope_object.is_null()) {
11968 return Handle<Context>::null();
11969 }
11970 // Allocate a new function context for the debug evaluation and set the
11971 // extension object.
11972 Handle<Context> new_context =
11973 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11974 function);
11975 new_context->set_extension(*block_scope_object);
11976 new_context->set_previous(*context);
11977 context = new_context;
11978 } else {
11979 ASSERT(scope_info->Type() == WITH_SCOPE);
11980 ASSERT(current->IsWithContext());
11981 Handle<JSObject> extension(JSObject::cast(current->extension()));
11982 context =
11983 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011984 }
erikcorry0ad885c2011-11-21 13:51:57 +000011985 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011986
11987 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988}
11989
11990
11991// Helper function to find or create the arguments object for
11992// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011993static Handle<Object> GetArgumentsObject(Isolate* isolate,
11994 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011995 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011997 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998 Handle<Context> function_context) {
11999 // Try to find the value of 'arguments' to pass as parameter. If it is not
12000 // found (that is the debugged function does not reference 'arguments' and
12001 // does not support eval) then create an 'arguments' object.
12002 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012003 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012004 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012006 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012007 }
12008 }
12009
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012010 if (scope_info->HasHeapAllocatedLocals()) {
12011 VariableMode mode;
12012 InitializationFlag init_flag;
12013 index = scope_info->ContextSlotIndex(
12014 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012015 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012016 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012017 }
12018 }
12019
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012020 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12021
12022 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012023 Handle<JSObject> arguments =
12024 isolate->factory()->NewArgumentsObject(function, length);
12025 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012026
12027 AssertNoAllocation no_gc;
12028 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012029 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012030 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012031 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012032 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012033 return arguments;
12034}
12035
12036
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012037static const char kSourceStr[] =
12038 "(function(arguments,__source__){return eval(__source__);})";
12039
12040
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012041// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012042// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012043// extension part has all the parameters and locals of the function on the
12044// stack frame. A function which calls eval with the code to evaluate is then
12045// compiled in this context and called in this context. As this context
12046// replaces the context of the function on the stack frame a new (empty)
12047// function is created as well to be used as the closure for the context.
12048// This function and the context acts as replacements for the function on the
12049// stack frame presenting the same view of the values of parameters and
12050// local variables as if the piece of JavaScript was evaluated at the point
12051// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012052RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012053 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012054
12055 // Check the execution state and decode arguments frame and source to be
12056 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012057 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012058 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012059 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12060 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012061 if (!maybe_check_result->ToObject(&check_result)) {
12062 return maybe_check_result;
12063 }
12064 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012065 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012066 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12067 CONVERT_ARG_CHECKED(String, source, 3);
12068 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12069 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012070
12071 // Handle the processing of break.
12072 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012073
12074 // Get the frame where the debugging is performed.
12075 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012076 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012077 JavaScriptFrame* frame = it.frame();
12078 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012079 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012080
12081 // Traverse the saved contexts chain to find the active context for the
12082 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012083 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12084
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012085 SaveContext savex(isolate);
12086 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012087
12088 // Create the (empty) function replacing the function on the stack frame for
12089 // the purpose of evaluating in the context created below. It is important
12090 // that this function does not describe any parameters and local variables
12091 // in the context. If it does then this will cause problems with the lookup
12092 // in Context::Lookup, where context slots for parameters and local variables
12093 // are looked at before the extension object.
12094 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012095 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12096 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097 go_between->set_context(function->context());
12098#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012099 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12100 ASSERT(go_between_scope_info->ParameterCount() == 0);
12101 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012102#endif
12103
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012104 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012105 Handle<JSObject> local_scope = MaterializeLocalScope(
12106 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012107 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012108
12109 // Allocate a new context for the debug evaluation and set the extension
12110 // object build.
12111 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012112 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12113 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012114 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012115 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012116 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012117 Handle<Context> function_context;
12118 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012119 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012120 function_context = Handle<Context>(frame_context->declaration_context());
12121 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012122 context = CopyNestedScopeContextChain(isolate,
12123 go_between,
12124 context,
12125 frame,
12126 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012128 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012129 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012130 context =
12131 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012132 }
12133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 // Wrap the evaluation statement in a new function compiled in the newly
12135 // created context. The function has one parameter which has to be called
12136 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012137 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012138 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012139
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012141 isolate->factory()->NewStringFromAscii(
12142 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012143
12144 // Currently, the eval code will be executed in non-strict mode,
12145 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012146 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012147 Compiler::CompileEval(function_source,
12148 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012149 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012150 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012151 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012152 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012154 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012155
12156 // Invoke the result of the compilation to get the evaluation function.
12157 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012158 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012159 Handle<Object> evaluation_function =
12160 Execution::Call(compiled_function, receiver, 0, NULL,
12161 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012162 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012164 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012165 frame,
12166 inlined_frame_index,
12167 function,
12168 scope_info,
12169 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012170
12171 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012172 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012173 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012174 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12175 receiver,
12176 ARRAY_SIZE(argv),
12177 argv,
12178 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012179 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012180
12181 // Skip the global proxy as it has no properties and always delegates to the
12182 // real global object.
12183 if (result->IsJSGlobalProxy()) {
12184 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12185 }
12186
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012187 return *result;
12188}
12189
12190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012191RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012192 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012193
12194 // Check the execution state and decode arguments frame and source to be
12195 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012196 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012197 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012198 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12199 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012200 if (!maybe_check_result->ToObject(&check_result)) {
12201 return maybe_check_result;
12202 }
12203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012205 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012206 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012207
12208 // Handle the processing of break.
12209 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210
12211 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012212 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012214 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215 top = top->prev();
12216 }
12217 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012218 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012219 }
12220
12221 // Get the global context now set to the top context from before the
12222 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012223 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012224
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012225 bool is_global = true;
12226
12227 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012228 // Create a new with context with the additional context information between
12229 // the context of the debugged function and the eval code to be executed.
12230 context = isolate->factory()->NewWithContext(
12231 Handle<JSFunction>(context->closure()),
12232 context,
12233 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012234 is_global = false;
12235 }
12236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012237 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012238 // Currently, the eval code will be executed in non-strict mode,
12239 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012240 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012241 Compiler::CompileEval(source,
12242 context,
12243 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012244 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012245 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012246 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012247 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012248 Handle<JSFunction>(
12249 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12250 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251
12252 // Invoke the result of the compilation to get the evaluation function.
12253 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012254 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012255 Handle<Object> result =
12256 Execution::Call(compiled_function, receiver, 0, NULL,
12257 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012258 // Clear the oneshot breakpoints so that the debugger does not step further.
12259 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012260 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012261 return *result;
12262}
12263
12264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012265RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012266 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012267 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012270 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012271
12272 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012273 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012274 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12275 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12276 // because using
12277 // instances->set(i, *GetScriptWrapper(script))
12278 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12279 // already have deferenced the instances handle.
12280 Handle<JSValue> wrapper = GetScriptWrapper(script);
12281 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282 }
12283
12284 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012285 Handle<JSObject> result =
12286 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012287 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288 return *result;
12289}
12290
12291
12292// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012293static int DebugReferencedBy(HeapIterator* iterator,
12294 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012295 Object* instance_filter, int max_references,
12296 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297 JSFunction* arguments_function) {
12298 NoHandleAllocation ha;
12299 AssertNoAllocation no_alloc;
12300
12301 // Iterate the heap.
12302 int count = 0;
12303 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012304 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012305 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012306 (max_references == 0 || count < max_references)) {
12307 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012308 if (heap_obj->IsJSObject()) {
12309 // Skip context extension objects and argument arrays as these are
12310 // checked in the context of functions using them.
12311 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012312 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012313 obj->map()->constructor() == arguments_function) {
12314 continue;
12315 }
12316
12317 // Check if the JS object has a reference to the object looked for.
12318 if (obj->ReferencesObject(target)) {
12319 // Check instance filter if supplied. This is normally used to avoid
12320 // references from mirror objects (see Runtime_IsInPrototypeChain).
12321 if (!instance_filter->IsUndefined()) {
12322 Object* V = obj;
12323 while (true) {
12324 Object* prototype = V->GetPrototype();
12325 if (prototype->IsNull()) {
12326 break;
12327 }
12328 if (instance_filter == prototype) {
12329 obj = NULL; // Don't add this object.
12330 break;
12331 }
12332 V = prototype;
12333 }
12334 }
12335
12336 if (obj != NULL) {
12337 // Valid reference found add to instance array if supplied an update
12338 // count.
12339 if (instances != NULL && count < instances_size) {
12340 instances->set(count, obj);
12341 }
12342 last = obj;
12343 count++;
12344 }
12345 }
12346 }
12347 }
12348
12349 // Check for circular reference only. This can happen when the object is only
12350 // referenced from mirrors and has a circular reference in which case the
12351 // object is not really alive and would have been garbage collected if not
12352 // referenced from the mirror.
12353 if (count == 1 && last == target) {
12354 count = 0;
12355 }
12356
12357 // Return the number of referencing objects found.
12358 return count;
12359}
12360
12361
12362// Scan the heap for objects with direct references to an object
12363// args[0]: the object to find references to
12364// args[1]: constructor function for instances to exclude (Mirror)
12365// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012366RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012367 ASSERT(args.length() == 3);
12368
12369 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012370 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12371 // The heap iterator reserves the right to do a GC to make the heap iterable.
12372 // Due to the GC above we know it won't need to do that, but it seems cleaner
12373 // to get the heap iterator constructed before we start having unprotected
12374 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012375
12376 // Check parameters.
12377 CONVERT_CHECKED(JSObject, target, args[0]);
12378 Object* instance_filter = args[1];
12379 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12380 instance_filter->IsJSObject());
12381 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12382 RUNTIME_ASSERT(max_references >= 0);
12383
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012385 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012386 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012387 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012388 JSFunction* arguments_function =
12389 JSFunction::cast(arguments_boilerplate->map()->constructor());
12390
12391 // Get the number of referencing objects.
12392 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012393 HeapIterator heap_iterator;
12394 count = DebugReferencedBy(&heap_iterator,
12395 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012396 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012397
12398 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012399 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012400 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012401 if (!maybe_object->ToObject(&object)) return maybe_object;
12402 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012403 FixedArray* instances = FixedArray::cast(object);
12404
12405 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012406 // AllocateFixedArray above does not make the heap non-iterable.
12407 ASSERT(HEAP->IsHeapIterable());
12408 HeapIterator heap_iterator2;
12409 count = DebugReferencedBy(&heap_iterator2,
12410 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012411 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012412
12413 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012414 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012415 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012416 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012417 if (!maybe_result->ToObject(&result)) return maybe_result;
12418 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012419}
12420
12421
12422// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012423static int DebugConstructedBy(HeapIterator* iterator,
12424 JSFunction* constructor,
12425 int max_references,
12426 FixedArray* instances,
12427 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012428 AssertNoAllocation no_alloc;
12429
12430 // Iterate the heap.
12431 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012432 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012433 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012434 (max_references == 0 || count < max_references)) {
12435 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012436 if (heap_obj->IsJSObject()) {
12437 JSObject* obj = JSObject::cast(heap_obj);
12438 if (obj->map()->constructor() == constructor) {
12439 // Valid reference found add to instance array if supplied an update
12440 // count.
12441 if (instances != NULL && count < instances_size) {
12442 instances->set(count, obj);
12443 }
12444 count++;
12445 }
12446 }
12447 }
12448
12449 // Return the number of referencing objects found.
12450 return count;
12451}
12452
12453
12454// Scan the heap for objects constructed by a specific function.
12455// args[0]: the constructor to find instances of
12456// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012457RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012458 ASSERT(args.length() == 2);
12459
12460 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012461 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012462
12463 // Check parameters.
12464 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12465 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12466 RUNTIME_ASSERT(max_references >= 0);
12467
12468 // Get the number of referencing objects.
12469 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012470 HeapIterator heap_iterator;
12471 count = DebugConstructedBy(&heap_iterator,
12472 constructor,
12473 max_references,
12474 NULL,
12475 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012476
12477 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012478 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012479 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012480 if (!maybe_object->ToObject(&object)) return maybe_object;
12481 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482 FixedArray* instances = FixedArray::cast(object);
12483
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012484 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012485 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012486 HeapIterator heap_iterator2;
12487 count = DebugConstructedBy(&heap_iterator2,
12488 constructor,
12489 max_references,
12490 instances,
12491 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012492
12493 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012494 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12496 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012497 if (!maybe_result->ToObject(&result)) return maybe_result;
12498 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012499 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012500}
12501
12502
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012503// Find the effective prototype object as returned by __proto__.
12504// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012505RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012506 ASSERT(args.length() == 1);
12507
12508 CONVERT_CHECKED(JSObject, obj, args[0]);
12509
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012510 // Use the __proto__ accessor.
12511 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012512}
12513
12514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012515RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012516 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012517 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012518 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012519}
12520
12521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012522RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012523#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012524 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012525 ASSERT(args.length() == 1);
12526 // Get the function and make sure it is compiled.
12527 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012528 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012529 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012530 return Failure::Exception();
12531 }
12532 func->code()->PrintLn();
12533#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012534 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012535}
ager@chromium.org9085a012009-05-11 19:22:57 +000012536
12537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012538RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012539#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012540 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012541 ASSERT(args.length() == 1);
12542 // Get the function and make sure it is compiled.
12543 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012544 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012545 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012546 return Failure::Exception();
12547 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012548 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012549#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012550 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012551}
12552
12553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012554RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012555 NoHandleAllocation ha;
12556 ASSERT(args.length() == 1);
12557
12558 CONVERT_CHECKED(JSFunction, f, args[0]);
12559 return f->shared()->inferred_name();
12560}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012561
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012562
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012563static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12564 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012565 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012566 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012567 int counter = 0;
12568 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012569 for (HeapObject* obj = iterator->next();
12570 obj != NULL;
12571 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012572 ASSERT(obj != NULL);
12573 if (!obj->IsSharedFunctionInfo()) {
12574 continue;
12575 }
12576 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12577 if (shared->script() != script) {
12578 continue;
12579 }
12580 if (counter < buffer_size) {
12581 buffer->set(counter, shared);
12582 }
12583 counter++;
12584 }
12585 return counter;
12586}
12587
12588// For a script finds all SharedFunctionInfo's in the heap that points
12589// to this script. Returns JSArray of SharedFunctionInfo wrapped
12590// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012591RUNTIME_FUNCTION(MaybeObject*,
12592 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012593 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012594 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012595 CONVERT_CHECKED(JSValue, script_value, args[0]);
12596
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012597
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012598 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12599
12600 const int kBufferSize = 32;
12601
12602 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012603 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012604 int number;
12605 {
12606 isolate->heap()->EnsureHeapIsIterable();
12607 AssertNoAllocation no_allocations;
12608 HeapIterator heap_iterator;
12609 Script* scr = *script;
12610 FixedArray* arr = *array;
12611 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12612 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012613 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012614 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012615 isolate->heap()->EnsureHeapIsIterable();
12616 AssertNoAllocation no_allocations;
12617 HeapIterator heap_iterator;
12618 Script* scr = *script;
12619 FixedArray* arr = *array;
12620 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012621 }
12622
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012623 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012624 result->set_length(Smi::FromInt(number));
12625
12626 LiveEdit::WrapSharedFunctionInfos(result);
12627
12628 return *result;
12629}
12630
12631// For a script calculates compilation information about all its functions.
12632// The script source is explicitly specified by the second argument.
12633// The source of the actual script is not used, however it is important that
12634// all generated code keeps references to this particular instance of script.
12635// Returns a JSArray of compilation infos. The array is ordered so that
12636// each function with all its descendant is always stored in a continues range
12637// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012638RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012639 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012640 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012641 CONVERT_CHECKED(JSValue, script, args[0]);
12642 CONVERT_ARG_CHECKED(String, source, 1);
12643 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12644
12645 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12646
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012647 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012648 return Failure::Exception();
12649 }
12650
12651 return result;
12652}
12653
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012654// Changes the source of the script to a new_source.
12655// If old_script_name is provided (i.e. is a String), also creates a copy of
12656// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012657RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012658 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012659 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012660 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12661 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012662 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012663
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012664 CONVERT_CHECKED(Script, original_script_pointer,
12665 original_script_value->value());
12666 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012667
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012668 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12669 new_source,
12670 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012671
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012672 if (old_script->IsScript()) {
12673 Handle<Script> script_handle(Script::cast(old_script));
12674 return *(GetScriptWrapper(script_handle));
12675 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012676 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012677 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012678}
12679
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012681RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012682 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012684 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12685 return LiveEdit::FunctionSourceUpdated(shared_info);
12686}
12687
12688
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012689// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012690RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012691 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012692 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012693 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12694 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12695
ager@chromium.orgac091b72010-05-05 07:34:42 +000012696 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012697}
12698
12699// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012700RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012701 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012702 HandleScope scope(isolate);
12703 Handle<Object> function_object(args[0], isolate);
12704 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012705
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012706 if (function_object->IsJSValue()) {
12707 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12708 if (script_object->IsJSValue()) {
12709 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012710 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012711 }
12712
12713 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12714 } else {
12715 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12716 // and we check it in this function.
12717 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012718
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012719 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012720}
12721
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012722
12723// In a code of a parent function replaces original function as embedded object
12724// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012725RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012726 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012727 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012728
12729 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12730 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12731 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12732
12733 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12734 subst_wrapper);
12735
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012736 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012737}
12738
12739
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012740// Updates positions of a shared function info (first parameter) according
12741// to script source change. Text change is described in second parameter as
12742// array of groups of 3 numbers:
12743// (change_begin, change_end, change_end_new_position).
12744// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012745RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012746 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012747 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012748 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12749 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12750
ager@chromium.orgac091b72010-05-05 07:34:42 +000012751 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012752}
12753
12754
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012755// For array of SharedFunctionInfo's (each wrapped in JSValue)
12756// checks that none of them have activations on stacks (of any thread).
12757// Returns array of the same length with corresponding results of
12758// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012759RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012760 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012761 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012762 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012763 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012764
ager@chromium.org357bf652010-04-12 11:30:10 +000012765 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012766}
12767
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012768// Compares 2 strings line-by-line, then token-wise and returns diff in form
12769// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12770// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012771RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012772 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012774 CONVERT_ARG_CHECKED(String, s1, 0);
12775 CONVERT_ARG_CHECKED(String, s2, 1);
12776
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012777 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012778}
12779
12780
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012781// A testing entry. Returns statement position which is the closest to
12782// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012783RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012784 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012785 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012786 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12787 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12788
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012789 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012790
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012791 if (code->kind() != Code::FUNCTION &&
12792 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012793 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012794 }
12795
12796 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012797 int closest_pc = 0;
12798 int distance = kMaxInt;
12799 while (!it.done()) {
12800 int statement_position = static_cast<int>(it.rinfo()->data());
12801 // Check if this break point is closer that what was previously found.
12802 if (source_position <= statement_position &&
12803 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012804 closest_pc =
12805 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012806 distance = statement_position - source_position;
12807 // Check whether we can't get any closer.
12808 if (distance == 0) break;
12809 }
12810 it.next();
12811 }
12812
12813 return Smi::FromInt(closest_pc);
12814}
12815
12816
ager@chromium.org357bf652010-04-12 11:30:10 +000012817// Calls specified function with or without entering the debugger.
12818// This is used in unit tests to run code as if debugger is entered or simply
12819// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012820RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012821 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012822 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012823 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12824 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12825
12826 Handle<Object> result;
12827 bool pending_exception;
12828 {
12829 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012830 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012831 &pending_exception);
12832 } else {
12833 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012834 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012835 &pending_exception);
12836 }
12837 }
12838 if (!pending_exception) {
12839 return *result;
12840 } else {
12841 return Failure::Exception();
12842 }
12843}
12844
12845
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012846// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012847RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012848 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012849 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012850 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12851 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012852 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012853}
12854
12855
12856// Performs a GC.
12857// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012858RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012859 isolate->heap()->CollectAllGarbage(true);
12860 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012861}
12862
12863
12864// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012865RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012866 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012867 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012868 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012869 }
12870 return Smi::FromInt(usage);
12871}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012872
12873
12874// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012875RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012876#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012877 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012878#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012879 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012880#endif
12881}
12882
12883
12884// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012885RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012886#ifdef LIVE_OBJECT_LIST
12887 return LiveObjectList::Capture();
12888#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012889 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012890#endif
12891}
12892
12893
12894// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012895RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012896#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012897 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012898 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012899 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012900#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012901 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012902#endif
12903}
12904
12905
12906// Generates the response to a debugger request for a dump of the objects
12907// contained in the difference between the captured live object lists
12908// specified by id1 and id2.
12909// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12910// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012911RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012912#ifdef LIVE_OBJECT_LIST
12913 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012914 CONVERT_SMI_ARG_CHECKED(id1, 0);
12915 CONVERT_SMI_ARG_CHECKED(id2, 1);
12916 CONVERT_SMI_ARG_CHECKED(start, 2);
12917 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012918 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12919 EnterDebugger enter_debugger;
12920 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12921#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012922 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012923#endif
12924}
12925
12926
12927// Gets the specified object as requested by the debugger.
12928// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012929RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012930#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012931 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012932 Object* result = LiveObjectList::GetObj(obj_id);
12933 return result;
12934#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012935 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012936#endif
12937}
12938
12939
12940// Gets the obj id for the specified address if valid.
12941// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012942RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012943#ifdef LIVE_OBJECT_LIST
12944 HandleScope scope;
12945 CONVERT_ARG_CHECKED(String, address, 0);
12946 Object* result = LiveObjectList::GetObjId(address);
12947 return result;
12948#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012950#endif
12951}
12952
12953
12954// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012955RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012956#ifdef LIVE_OBJECT_LIST
12957 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012958 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012959 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12960 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12961 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12962 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12963 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12964
12965 Handle<JSObject> instance_filter;
12966 if (args[1]->IsJSObject()) {
12967 instance_filter = args.at<JSObject>(1);
12968 }
12969 bool verbose = false;
12970 if (args[2]->IsBoolean()) {
12971 verbose = args[2]->IsTrue();
12972 }
12973 int start = 0;
12974 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012975 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012976 }
12977 int limit = Smi::kMaxValue;
12978 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012979 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012980 }
12981
12982 return LiveObjectList::GetObjRetainers(obj_id,
12983 instance_filter,
12984 verbose,
12985 start,
12986 limit,
12987 filter_obj);
12988#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012989 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012990#endif
12991}
12992
12993
12994// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012996#ifdef LIVE_OBJECT_LIST
12997 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012998 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12999 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013000 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13001
13002 Handle<JSObject> instance_filter;
13003 if (args[2]->IsJSObject()) {
13004 instance_filter = args.at<JSObject>(2);
13005 }
13006
13007 Object* result =
13008 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13009 return result;
13010#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013011 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013012#endif
13013}
13014
13015
13016// Generates the response to a debugger request for a list of all
13017// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013018RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013019#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013020 CONVERT_SMI_ARG_CHECKED(start, 0);
13021 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013022 return LiveObjectList::Info(start, count);
13023#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013024 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013025#endif
13026}
13027
13028
13029// Gets a dump of the specified object as requested by the debugger.
13030// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013031RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013032#ifdef LIVE_OBJECT_LIST
13033 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013034 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013035 Object* result = LiveObjectList::PrintObj(obj_id);
13036 return result;
13037#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013038 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013039#endif
13040}
13041
13042
13043// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013044RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013045#ifdef LIVE_OBJECT_LIST
13046 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013047 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013048#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013049 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013050#endif
13051}
13052
13053
13054// Generates the response to a debugger request for a summary of the types
13055// of objects in the difference between the captured live object lists
13056// specified by id1 and id2.
13057// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13058// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013059RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013060#ifdef LIVE_OBJECT_LIST
13061 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013062 CONVERT_SMI_ARG_CHECKED(id1, 0);
13063 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013064 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13065
13066 EnterDebugger enter_debugger;
13067 return LiveObjectList::Summarize(id1, id2, filter_obj);
13068#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013069 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013070#endif
13071}
13072
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013073#endif // ENABLE_DEBUGGER_SUPPORT
13074
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013076RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013077 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013078 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013079 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013080}
13081
13082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013083RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013084 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013085 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013086 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013087}
13088
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013089
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013090// Finds the script object from the script data. NOTE: This operation uses
13091// heap traversal to find the function generated for the source position
13092// for the requested break point. For lazily compiled functions several heap
13093// traversals might be required rendering this operation as a rather slow
13094// operation. However for setting break points which is normally done through
13095// some kind of user interaction the performance is not crucial.
13096static Handle<Object> Runtime_GetScriptFromScriptName(
13097 Handle<String> script_name) {
13098 // Scan the heap for Script objects to find the script with the requested
13099 // script data.
13100 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013101 script_name->GetHeap()->EnsureHeapIsIterable();
13102 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013103 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013104 HeapObject* obj = NULL;
13105 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013106 // If a script is found check if it has the script data requested.
13107 if (obj->IsScript()) {
13108 if (Script::cast(obj)->name()->IsString()) {
13109 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13110 script = Handle<Script>(Script::cast(obj));
13111 }
13112 }
13113 }
13114 }
13115
13116 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013117 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013118
13119 // Return the script found.
13120 return GetScriptWrapper(script);
13121}
13122
13123
13124// Get the script object from script data. NOTE: Regarding performance
13125// see the NOTE for GetScriptFromScriptData.
13126// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013127RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013128 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013129
13130 ASSERT(args.length() == 1);
13131
13132 CONVERT_CHECKED(String, script_name, args[0]);
13133
13134 // Find the requested script.
13135 Handle<Object> result =
13136 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13137 return *result;
13138}
13139
13140
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013141// Determines whether the given stack frame should be displayed in
13142// a stack trace. The caller is the error constructor that asked
13143// for the stack trace to be collected. The first time a construct
13144// call to this function is encountered it is skipped. The seen_caller
13145// in/out parameter is used to remember if the caller has been seen
13146// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013147static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13148 Object* caller,
13149 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013150 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013151 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013152 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013153 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013154 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13155 Object* raw_fun = frame->function();
13156 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013157 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013158 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013159 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013160 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013161 *seen_caller = true;
13162 return false;
13163 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013164 // Skip all frames until we've seen the caller.
13165 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013166 // Also, skip non-visible built-in functions and any call with the builtins
13167 // object as receiver, so as to not reveal either the builtins object or
13168 // an internal function.
13169 // The --builtins-in-stack-traces command line flag allows including
13170 // internal call sites in the stack trace for debugging purposes.
13171 if (!FLAG_builtins_in_stack_traces) {
13172 JSFunction* fun = JSFunction::cast(raw_fun);
13173 if (frame->receiver()->IsJSBuiltinsObject() ||
13174 (fun->IsBuiltin() && !fun->shared()->native())) {
13175 return false;
13176 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013177 }
13178 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013179}
13180
13181
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013182// Collect the raw data for a stack trace. Returns an array of 4
13183// element segments each containing a receiver, function, code and
13184// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013185RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013186 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013187 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013188 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13189
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013190 HandleScope scope(isolate);
13191 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013192
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013193 limit = Max(limit, 0); // Ensure that limit is not negative.
13194 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013195 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013196 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013197
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013198 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013199 // If the caller parameter is a function we skip frames until we're
13200 // under it before starting to collect.
13201 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013202 int cursor = 0;
13203 int frames_seen = 0;
13204 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013205 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013206 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013207 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013208 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013209 // Set initial size to the maximum inlining level + 1 for the outermost
13210 // function.
13211 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013212 frame->Summarize(&frames);
13213 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013214 if (cursor + 4 > elements->length()) {
13215 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13216 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013217 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013218 for (int i = 0; i < cursor; i++) {
13219 new_elements->set(i, elements->get(i));
13220 }
13221 elements = new_elements;
13222 }
13223 ASSERT(cursor + 4 <= elements->length());
13224
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013225 Handle<Object> recv = frames[i].receiver();
13226 Handle<JSFunction> fun = frames[i].function();
13227 Handle<Code> code = frames[i].code();
13228 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013229 elements->set(cursor++, *recv);
13230 elements->set(cursor++, *fun);
13231 elements->set(cursor++, *code);
13232 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013233 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013234 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013235 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013236 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013237 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013238 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013239 return *result;
13240}
13241
13242
ager@chromium.org3811b432009-10-28 14:53:37 +000013243// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013244RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013245 ASSERT_EQ(args.length(), 0);
13246
13247 NoHandleAllocation ha;
13248
13249 const char* version_string = v8::V8::GetVersion();
13250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013251 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13252 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013253}
13254
13255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013256RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013257 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013258 OS::PrintError("abort: %s\n",
13259 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013260 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013261 OS::Abort();
13262 UNREACHABLE();
13263 return NULL;
13264}
13265
13266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013267RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013268 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013269 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013270 Object* key = args[1];
13271
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013272 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013273 Object* o = cache->get(finger_index);
13274 if (o == key) {
13275 // The fastest case: hit the same place again.
13276 return cache->get(finger_index + 1);
13277 }
13278
13279 for (int i = finger_index - 2;
13280 i >= JSFunctionResultCache::kEntriesIndex;
13281 i -= 2) {
13282 o = cache->get(i);
13283 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013284 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013285 return cache->get(i + 1);
13286 }
13287 }
13288
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013289 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013290 ASSERT(size <= cache->length());
13291
13292 for (int i = size - 2; i > finger_index; i -= 2) {
13293 o = cache->get(i);
13294 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013295 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013296 return cache->get(i + 1);
13297 }
13298 }
13299
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013300 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013301 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013302
13303 Handle<JSFunctionResultCache> cache_handle(cache);
13304 Handle<Object> key_handle(key);
13305 Handle<Object> value;
13306 {
13307 Handle<JSFunction> factory(JSFunction::cast(
13308 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13309 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013310 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013311 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013312 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013313 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013314 value = Execution::Call(factory,
13315 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013316 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013317 argv,
13318 &pending_exception);
13319 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013320 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013321
13322#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013323 if (FLAG_verify_heap) {
13324 cache_handle->JSFunctionResultCacheVerify();
13325 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013326#endif
13327
13328 // Function invocation may have cleared the cache. Reread all the data.
13329 finger_index = cache_handle->finger_index();
13330 size = cache_handle->size();
13331
13332 // If we have spare room, put new data into it, otherwise evict post finger
13333 // entry which is likely to be the least recently used.
13334 int index = -1;
13335 if (size < cache_handle->length()) {
13336 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13337 index = size;
13338 } else {
13339 index = finger_index + JSFunctionResultCache::kEntrySize;
13340 if (index == cache_handle->length()) {
13341 index = JSFunctionResultCache::kEntriesIndex;
13342 }
13343 }
13344
13345 ASSERT(index % 2 == 0);
13346 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13347 ASSERT(index < cache_handle->length());
13348
13349 cache_handle->set(index, *key_handle);
13350 cache_handle->set(index + 1, *value);
13351 cache_handle->set_finger_index(index);
13352
13353#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013354 if (FLAG_verify_heap) {
13355 cache_handle->JSFunctionResultCacheVerify();
13356 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013357#endif
13358
13359 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013360}
13361
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013363RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013364 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013365 CONVERT_ARG_CHECKED(String, type, 0);
13366 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013367 return *isolate->factory()->NewJSMessageObject(
13368 type,
13369 arguments,
13370 0,
13371 0,
13372 isolate->factory()->undefined_value(),
13373 isolate->factory()->undefined_value(),
13374 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013375}
13376
13377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013378RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013379 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13380 return message->type();
13381}
13382
13383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013384RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013385 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13386 return message->arguments();
13387}
13388
13389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013390RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013391 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13392 return Smi::FromInt(message->start_position());
13393}
13394
13395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013396RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013397 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13398 return message->script();
13399}
13400
13401
kasper.lund44510672008-07-25 07:37:58 +000013402#ifdef DEBUG
13403// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13404// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013405RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013406 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013407 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013408#define COUNT_ENTRY(Name, argc, ressize) + 1
13409 int entry_count = 0
13410 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13411 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13412 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13413#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013414 Factory* factory = isolate->factory();
13415 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013416 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013417 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013418#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013419 { \
13420 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013421 Handle<String> name; \
13422 /* Inline runtime functions have an underscore in front of the name. */ \
13423 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013424 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013425 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13426 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013427 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013428 Vector<const char>(#Name, StrLength(#Name))); \
13429 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013430 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013431 pair_elements->set(0, *name); \
13432 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013433 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013434 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013435 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013436 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013437 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013438 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013439 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013440 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013441#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013442 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013443 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013444 return *result;
13445}
kasper.lund44510672008-07-25 07:37:58 +000013446#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013447
13448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013449RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013450 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013451 CONVERT_CHECKED(String, format, args[0]);
13452 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013453 String::FlatContent format_content = format->GetFlatContent();
13454 RUNTIME_ASSERT(format_content.IsAscii());
13455 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013456 LOGGER->LogRuntime(chars, elms);
13457 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013458}
13459
13460
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013461RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013462 UNREACHABLE(); // implemented as macro in the parser
13463 return NULL;
13464}
13465
13466
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013467#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13468 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13469 CONVERT_CHECKED(JSObject, obj, args[0]); \
13470 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13471 }
13472
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013473ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013474ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13475ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13476ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13477ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13478ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13479ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13480ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13481ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13482ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13483ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13484ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13485ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13486ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13487
13488#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13489
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013490
13491RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13492 ASSERT(args.length() == 2);
13493 CONVERT_CHECKED(JSObject, obj1, args[0]);
13494 CONVERT_CHECKED(JSObject, obj2, args[1]);
13495 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13496}
13497
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013498// ----------------------------------------------------------------------------
13499// Implementation of Runtime
13500
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013501#define F(name, number_of_args, result_size) \
13502 { Runtime::k##name, Runtime::RUNTIME, #name, \
13503 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013504
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013505
13506#define I(name, number_of_args, result_size) \
13507 { Runtime::kInline##name, Runtime::INLINE, \
13508 "_" #name, NULL, number_of_args, result_size },
13509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013510static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013511 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013512 INLINE_FUNCTION_LIST(I)
13513 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013514};
13515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013517MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13518 Object* dictionary) {
13519 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013520 ASSERT(dictionary != NULL);
13521 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13522 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013523 Object* name_symbol;
13524 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013525 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013526 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13527 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013528 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013529 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13530 String::cast(name_symbol),
13531 Smi::FromInt(i),
13532 PropertyDetails(NONE, NORMAL));
13533 if (!maybe_dictionary->ToObject(&dictionary)) {
13534 // Non-recoverable failure. Calling code must restart heap
13535 // initialization.
13536 return maybe_dictionary;
13537 }
13538 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013539 }
13540 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013541}
13542
13543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013544const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13545 Heap* heap = name->GetHeap();
13546 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013547 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013548 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013549 int function_index = Smi::cast(smi_index)->value();
13550 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013551 }
13552 return NULL;
13553}
13554
13555
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013556const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013557 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13558}
13559
13560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013561void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013562 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013563 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013564 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013565 if (isolate->heap()->new_space()->AddFreshPage()) {
13566 return;
13567 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013568 // Try to do a garbage collection; ignore it if it fails. The C
13569 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013570 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013571 } else {
13572 // Handle last resort GC and make sure to allow future allocations
13573 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013574 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013575 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013577}
13578
13579
13580} } // namespace v8::internal